Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6f80e87 authored by Michael Schmitz's avatar Michael Schmitz Committed by Geert Uytterhoeven
Browse files

m68k/atari: EtherNAT - add interrupt chip definition for CPLD interrupts



Add a dedicated interrupt chip definition for the EtherNAT CPLD interrupts.
SMC91C111 and ISP1160 chips have separate interrupts that can be enabled
and disabled in a CPLD register at offset 0x23 from the card base.

Note the CPLD interrupt control register is mapped on demand, whenever any
interrupt enable/disable action is requested. The EtherNAT USB driver still
needs interrupts disabled around reset and start actions.
In particular, we cannot entirely rely on the irq_startup being called
first.

The smc91x and isp116x-hcd drivers will use this feature.

Signed-off-by: default avatarMichael Schmitz <schmitz@debian.org>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
parent 1d87a8f2
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <asm/atari_stdma.h>
#include <asm/irq.h>
#include <asm/entry.h>
#include <asm/io.h>


/*
@@ -177,6 +178,80 @@ static struct irq_chip atari_mfptimer_chip = {
	.irq_disable	= atari_mfptimer_disable,
};


/*
 * EtherNAT CPLD interrupt handling
 * CPLD interrupt register is at phys. 0x80000023
 * Need this mapped in at interrupt startup time
 * Possibly need this mapped on demand anyway -
 * EtherNAT USB driver needs to disable IRQ before
 * startup!
 */

static unsigned char *enat_cpld;

static unsigned int atari_ethernat_startup(struct irq_data *data)
{
	int enat_num = 140 - data->irq + 1;

	m68k_irq_startup(data);
	/*
	* map CPLD interrupt register
	*/
	if (!enat_cpld)
		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
	/*
	 * do _not_ enable the USB chip interrupt here - causes interrupt storm
	 * and triggers dead interrupt watchdog
	 * Need to reset the USB chip to a sane state in early startup before
	 * removing this hack
	 */
	if (enat_num == 1)
		*enat_cpld |= 1 << enat_num;

	return 0;
}

static void atari_ethernat_enable(struct irq_data *data)
{
	int enat_num = 140 - data->irq + 1;
	/*
	* map CPLD interrupt register
	*/
	if (!enat_cpld)
		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
	*enat_cpld |= 1 << enat_num;
}

static void atari_ethernat_disable(struct irq_data *data)
{
	int enat_num = 140 - data->irq + 1;
	/*
	* map CPLD interrupt register
	*/
	if (!enat_cpld)
		enat_cpld = (unsigned char *)ioremap((ATARI_ETHERNAT_PHYS_ADDR+0x23), 0x2);
	*enat_cpld &= ~(1 << enat_num);
}

static void atari_ethernat_shutdown(struct irq_data *data)
{
	int enat_num = 140 - data->irq + 1;
	if (enat_cpld) {
		*enat_cpld &= ~(1 << enat_num);
		iounmap(enat_cpld);
		enat_cpld = NULL;
	}
}

static struct irq_chip atari_ethernat_chip = {
	.name		= "ethernat",
	.irq_startup	= atari_ethernat_startup,
	.irq_shutdown	= atari_ethernat_shutdown,
	.irq_enable	= atari_ethernat_enable,
	.irq_disable	= atari_ethernat_disable,
};

/*
 * void atari_init_IRQ (void)
 *
@@ -268,6 +343,13 @@ void __init atari_init_IRQ(void)
	if (request_irq(IRQ_MFP_TIMD, mfptimer_handler, IRQF_SHARED,
			stmfp_base.name, &stmfp_base))
		pr_err("Couldn't register %s interrupt\n", stmfp_base.name);

	/*
	 * EtherNAT ethernet / USB interrupt handlers
	 */

	m68k_setup_irq_controller(&atari_ethernat_chip, handle_simple_irq,
				  139, 2);
}