m68k/q40: Replace q40ide driver with pata_falcon and falconide

This allows m68k q40 systems to switch from the deprecated IDE subsystem
to libata.

Enhance the byte-swapping falconide and pata_falcon platform drivers to
accept an irq resource, for use on q40. Atari ST-DMA IRQ arrangements seem
to co-exist with q40 IRQ arrangements without too much mess.

The new IO resources were added solely for the purpose of making
request_region() reservations identical to those made by q40ide: these
regions aren't used for actual IO.

Cc: Michael Schmitz <schmitzmic@gmail.com>
Cc: Richard Zidlicky <rz@linux-m68k.org>
Reviewed-and-tested-by: Michael Schmitz <schmitzmic@gmail.com>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
Link: https://lore.kernel.org/r/eefb7e9c2291e09fb4e065ce06bc105f05bb9e06.1623287706.git.fthain@linux-m68k.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Finn Thain 2021-06-10 11:15:06 +10:00 committed by Jens Axboe
parent cabd10be0b
commit 44b1fbc0f5
10 changed files with 147 additions and 251 deletions

View File

@ -875,16 +875,8 @@ static const struct resource atari_scsi_tt_rsrc[] __initconst = {
#define FALCON_IDE_BASE 0xfff00000
static const struct resource atari_falconide_rsrc[] __initconst = {
{
.flags = IORESOURCE_MEM,
.start = FALCON_IDE_BASE,
.end = FALCON_IDE_BASE + 0x39,
},
{
.flags = IORESOURCE_IRQ,
.start = IRQ_MFP_FSCSI,
.end = IRQ_MFP_FSCSI,
},
DEFINE_RES_MEM(FALCON_IDE_BASE, 0x38),
DEFINE_RES_MEM(FALCON_IDE_BASE + 0x38, 2),
};
int __init atari_platform_init(void)

View File

@ -351,7 +351,6 @@ CONFIG_BLK_DEV_PLATFORM=y
CONFIG_BLK_DEV_GAYLE=y
CONFIG_BLK_DEV_BUDDHA=y
CONFIG_BLK_DEV_FALCON_IDE=y
CONFIG_BLK_DEV_Q40IDE=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y

View File

@ -317,7 +317,7 @@ CONFIG_DUMMY_IRQ=m
CONFIG_IDE=y
CONFIG_IDE_GD_ATAPI=y
CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_Q40IDE=y
CONFIG_BLK_DEV_FALCON_IDE=y
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y

View File

@ -286,14 +286,39 @@ static int q40_set_rtc_pll(struct rtc_pll_info *pll)
return -EINVAL;
}
static __init int q40_add_kbd_device(void)
{
struct platform_device *pdev;
#define PCIDE_BASE1 0x1f0
#define PCIDE_BASE2 0x170
#define PCIDE_CTL 0x206
static const struct resource q40_pata_rsrc_0[] __initconst = {
DEFINE_RES_MEM(q40_isa_io_base + PCIDE_BASE1 * 4, 0x38),
DEFINE_RES_MEM(q40_isa_io_base + (PCIDE_BASE1 + PCIDE_CTL) * 4, 2),
DEFINE_RES_IO(PCIDE_BASE1, 8),
DEFINE_RES_IO(PCIDE_BASE1 + PCIDE_CTL, 1),
DEFINE_RES_IRQ(14),
};
static const struct resource q40_pata_rsrc_1[] __initconst = {
DEFINE_RES_MEM(q40_isa_io_base + PCIDE_BASE2 * 4, 0x38),
DEFINE_RES_MEM(q40_isa_io_base + (PCIDE_BASE2 + PCIDE_CTL) * 4, 2),
DEFINE_RES_IO(PCIDE_BASE2, 8),
DEFINE_RES_IO(PCIDE_BASE2 + PCIDE_CTL, 1),
DEFINE_RES_IRQ(15),
};
static __init int q40_platform_init(void)
{
if (!MACH_IS_Q40)
return -ENODEV;
pdev = platform_device_register_simple("q40kbd", -1, NULL, 0);
return PTR_ERR_OR_ZERO(pdev);
platform_device_register_simple("q40kbd", -1, NULL, 0);
platform_device_register_simple("atari-falcon-ide", 0, q40_pata_rsrc_0,
ARRAY_SIZE(q40_pata_rsrc_0));
platform_device_register_simple("atari-falcon-ide", 1, q40_pata_rsrc_1,
ARRAY_SIZE(q40_pata_rsrc_1));
return 0;
}
arch_initcall(q40_add_kbd_device);
arch_initcall(q40_platform_init);

View File

@ -1015,11 +1015,11 @@ config PATA_CMD640_PCI
If unsure, say N.
config PATA_FALCON
tristate "Atari Falcon PATA support"
depends on M68K && ATARI
tristate "Atari Falcon and Q40/Q60 PATA support"
depends on M68K && (ATARI || Q40)
help
This option enables support for the on-board IDE
interface on the Atari Falcon.
interface on the Atari Falcon and Q40/Q60.
If unsure, say N.

View File

@ -33,8 +33,6 @@
#define DRV_NAME "pata_falcon"
#define DRV_VERSION "0.1.0"
#define ATA_HD_CONTROL 0x39
static struct scsi_host_template pata_falcon_sht = {
ATA_PIO_SHT(DRV_NAME),
};
@ -121,23 +119,42 @@ static struct ata_port_operations pata_falcon_ops = {
static int __init pata_falcon_init_one(struct platform_device *pdev)
{
struct resource *res;
struct resource *base_mem_res, *ctl_mem_res;
struct resource *base_res, *ctl_res, *irq_res;
struct ata_host *host;
struct ata_port *ap;
void __iomem *base;
int irq = 0;
dev_info(&pdev->dev, "Atari Falcon PATA controller\n");
dev_info(&pdev->dev, "Atari Falcon and Q40/Q60 PATA controller\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), DRV_NAME)) {
base_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (base_res && !devm_request_region(&pdev->dev, base_res->start,
resource_size(base_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (ctl_res && !devm_request_region(&pdev->dev, ctl_res->start,
resource_size(ctl_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
base_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!base_mem_res)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, base_mem_res->start,
resource_size(base_mem_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
ctl_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!ctl_mem_res)
return -ENODEV;
/* allocate host */
host = ata_host_alloc(&pdev->dev, 1);
if (!host)
@ -147,10 +164,10 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
ap->ops = &pata_falcon_ops;
ap->pio_mask = ATA_PIO4;
ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
ap->flags |= ATA_FLAG_PIO_POLLING;
base = (void __iomem *)res->start;
ap->ioaddr.data_addr = base;
base = (void __iomem *)base_mem_res->start;
/* N.B. this assumes data_addr will be used for word-sized I/O only */
ap->ioaddr.data_addr = base + 0 + 0 * 4;
ap->ioaddr.error_addr = base + 1 + 1 * 4;
ap->ioaddr.feature_addr = base + 1 + 1 * 4;
ap->ioaddr.nsect_addr = base + 1 + 2 * 4;
@ -161,14 +178,25 @@ static int __init pata_falcon_init_one(struct platform_device *pdev)
ap->ioaddr.status_addr = base + 1 + 7 * 4;
ap->ioaddr.command_addr = base + 1 + 7 * 4;
ap->ioaddr.altstatus_addr = base + ATA_HD_CONTROL;
ap->ioaddr.ctl_addr = base + ATA_HD_CONTROL;
base = (void __iomem *)ctl_mem_res->start;
ap->ioaddr.altstatus_addr = base + 1;
ap->ioaddr.ctl_addr = base + 1;
ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", (unsigned long)base,
(unsigned long)base + ATA_HD_CONTROL);
ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx",
(unsigned long)base_mem_res->start,
(unsigned long)ctl_mem_res->start);
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res && irq_res->start > 0) {
irq = irq_res->start;
} else {
ap->flags |= ATA_FLAG_PIO_POLLING;
ata_port_desc(ap, "no IRQ, using PIO polling");
}
/* activate */
return ata_host_activate(host, 0, NULL, 0, &pata_falcon_sht);
return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
IRQF_SHARED, &pata_falcon_sht);
}
static int __exit pata_falcon_remove_one(struct platform_device *pdev)

View File

@ -731,21 +731,13 @@ config BLK_DEV_BUDDHA
to one of its IDE interfaces.
config BLK_DEV_FALCON_IDE
tristate "Falcon IDE interface support"
depends on ATARI
tristate "Falcon and Q40/Q60 IDE interface support"
depends on ATARI || Q40
help
This is the IDE driver for the on-board IDE interface on the Atari
Falcon. Say Y if you have a Falcon and want to use IDE devices (hard
disks, CD-ROM drives, etc.) that are connected to the on-board IDE
interface.
config BLK_DEV_Q40IDE
tristate "Q40/Q60 IDE interface support"
depends on Q40
help
Enable the on-board IDE controller in the Q40/Q60. This should
normally be on; disable it only if you are running a custom hard
drive subsystem through an expansion card.
Falcon and Q40/Q60. Say Y if you have such a machine and want to use
IDE devices (hard disks, CD-ROM drives, etc.) that are connected to
the on-board IDE interface.
config BLK_DEV_PALMCHIP_BK3710
tristate "Palmchip bk3710 IDE controller support"

View File

@ -29,7 +29,6 @@ obj-$(CONFIG_BLK_DEV_4DRIVES) += ide-4drives.o
obj-$(CONFIG_BLK_DEV_GAYLE) += gayle.o
obj-$(CONFIG_BLK_DEV_FALCON_IDE) += falconide.o
obj-$(CONFIG_BLK_DEV_Q40IDE) += q40ide.o
obj-$(CONFIG_BLK_DEV_BUDDHA) += buddha.o
obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o

View File

@ -25,12 +25,7 @@
#define DRV_NAME "falconide"
/*
* Offsets from base address
*/
#define ATA_HD_CONTROL 0x39
#ifdef CONFIG_ATARI
/*
* falconide_intr_lock is used to obtain access to the IDE interrupt,
* which is shared between several drivers.
@ -55,6 +50,7 @@ static void falconide_get_lock(irq_handler_t handler, void *data)
falconide_intr_lock = 1;
}
}
#endif
static void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
void *buf, unsigned int len)
@ -98,8 +94,10 @@ static const struct ide_tp_ops falconide_tp_ops = {
};
static const struct ide_port_info falconide_port_info = {
#ifdef CONFIG_ATARI
.get_lock = falconide_get_lock,
.release_lock = falconide_release_lock,
#endif
.tp_ops = &falconide_tp_ops,
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
IDE_HFLAG_NO_DMA,
@ -107,7 +105,8 @@ static const struct ide_port_info falconide_port_info = {
.chipset = ide_generic,
};
static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base,
unsigned long ctl, int irq)
{
int i;
@ -118,9 +117,9 @@ static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
for (i = 1; i < 8; i++)
hw->io_ports_array[i] = base + 1 + i * 4;
hw->io_ports.ctl_addr = base + ATA_HD_CONTROL;
hw->io_ports.ctl_addr = ctl + 1;
hw->irq = IRQ_MFP_IDE;
hw->irq = irq;
}
/*
@ -129,37 +128,69 @@ static void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base)
static int __init falconide_init(struct platform_device *pdev)
{
struct resource *res;
struct resource *base_mem_res, *ctl_mem_res;
struct resource *base_res, *ctl_res, *irq_res;
struct ide_host *host;
struct ide_hw hw, *hws[] = { &hw };
unsigned long base;
int rc;
int irq;
dev_info(&pdev->dev, "Atari Falcon IDE controller\n");
dev_info(&pdev->dev, "Atari Falcon and Q40/Q60 IDE controller\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, res->start,
resource_size(res), DRV_NAME)) {
base_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (base_res && !devm_request_region(&pdev->dev, base_res->start,
resource_size(base_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
base = (unsigned long)res->start;
falconide_setup_ports(&hw, base);
host = ide_host_alloc(&falconide_port_info, hws, 1);
if (host == NULL) {
rc = -ENOMEM;
goto err;
ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (ctl_res && !devm_request_region(&pdev->dev, ctl_res->start,
resource_size(ctl_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
falconide_get_lock(NULL, NULL);
base_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!base_mem_res)
return -ENODEV;
if (!devm_request_mem_region(&pdev->dev, base_mem_res->start,
resource_size(base_mem_res), DRV_NAME)) {
dev_err(&pdev->dev, "resources busy\n");
return -EBUSY;
}
ctl_mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!ctl_mem_res)
return -ENODEV;
if (MACH_IS_ATARI) {
irq = IRQ_MFP_IDE;
} else {
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_res && irq_res->start > 0)
irq = irq_res->start;
else
return -ENODEV;
}
falconide_setup_ports(&hw, base_mem_res->start, ctl_mem_res->start, irq);
host = ide_host_alloc(&falconide_port_info, hws, 1);
if (!host)
return -ENOMEM;
if (!MACH_IS_ATARI) {
host->get_lock = NULL;
host->release_lock = NULL;
}
if (host->get_lock)
host->get_lock(NULL, NULL);
rc = ide_host_register(host, &falconide_port_info, hws);
falconide_release_lock();
if (host->release_lock)
host->release_lock();
if (rc)
goto err_free;
@ -168,8 +199,6 @@ static int __init falconide_init(struct platform_device *pdev)
return 0;
err_free:
ide_host_free(host);
err:
release_mem_region(res->start, resource_size(res));
return rc;
}

View File

@ -1,168 +0,0 @@
/*
* Q40 I/O port IDE Driver
*
* (c) Richard Zidlicky
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*
*
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/ide.h>
#include <linux/module.h>
#include <asm/ide.h>
/*
* Bases of the IDE interfaces
*/
#define Q40IDE_NUM_HWIFS 2
#define PCIDE_BASE1 0x1f0
#define PCIDE_BASE2 0x170
#define PCIDE_BASE3 0x1e8
#define PCIDE_BASE4 0x168
#define PCIDE_BASE5 0x1e0
#define PCIDE_BASE6 0x160
static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
PCIDE_BASE6 */
};
static int q40ide_default_irq(unsigned long base)
{
switch (base) {
case 0x1f0: return 14;
case 0x170: return 15;
case 0x1e8: return 11;
default:
return 0;
}
}
/*
* Addresses are pretranslated for Q40 ISA access.
*/
static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
{
memset(hw, 0, sizeof(*hw));
/* BIG FAT WARNING:
assumption: only DATA port is ever used in 16 bit mode */
hw->io_ports.data_addr = Q40_ISA_IO_W(base);
hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
hw->irq = irq;
}
static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
void *buf, unsigned int len)
{
unsigned long data_addr = drive->hwif->io_ports.data_addr;
if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
__ide_mm_insw(data_addr, buf, (len + 1) / 2);
return;
}
raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
}
static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
void *buf, unsigned int len)
{
unsigned long data_addr = drive->hwif->io_ports.data_addr;
if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
__ide_mm_outsw(data_addr, buf, (len + 1) / 2);
return;
}
raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
}
/* Q40 has a byte-swapped IDE interface */
static const struct ide_tp_ops q40ide_tp_ops = {
.exec_command = ide_exec_command,
.read_status = ide_read_status,
.read_altstatus = ide_read_altstatus,
.write_devctl = ide_write_devctl,
.dev_select = ide_dev_select,
.tf_load = ide_tf_load,
.tf_read = ide_tf_read,
.input_data = q40ide_input_data,
.output_data = q40ide_output_data,
};
static const struct ide_port_info q40ide_port_info = {
.tp_ops = &q40ide_tp_ops,
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
.irq_flags = IRQF_SHARED,
.chipset = ide_generic,
};
/*
* the static array is needed to have the name reported in /proc/ioports,
* hwif->name unfortunately isn't available yet
*/
static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
"ide0", "ide1"
};
/*
* Probe for Q40 IDE interfaces
*/
static int __init q40ide_init(void)
{
int i;
struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
if (!MACH_IS_Q40)
return -ENODEV;
printk(KERN_INFO "ide: Q40 IDE controller\n");
for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
const char *name = q40_ide_names[i];
if (!request_region(pcide_bases[i], 8, name)) {
printk("could not reserve ports %lx-%lx for %s\n",
pcide_bases[i],pcide_bases[i]+8,name);
continue;
}
if (!request_region(pcide_bases[i]+0x206, 1, name)) {
printk("could not reserve port %lx for %s\n",
pcide_bases[i]+0x206,name);
release_region(pcide_bases[i], 8);
continue;
}
q40_ide_setup_ports(&hw[i], pcide_bases[i],
q40ide_default_irq(pcide_bases[i]));
hws[i] = &hw[i];
}
return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
}
module_init(q40ide_init);
MODULE_LICENSE("GPL");