sh: sh775x/titan fixes for irq header changes.

The following moves the creation of IPR interupts into setup-7750.c
and updates a few other things to make it all work after the "Drop
CPU subtype IRQ headers" commit. It boots and runs fine on my titan
board.

 - adds an ipr_idx to the ipr_data and uses a function in the subtype
   code to calculate the address of the IPR registers

 - adds a function to enable individual interrupt mode for externals
   in the subtype code and calls that from the titan board code
   instead of doing it directly.

 - I changed the shift in the ipr_data to be the actual # of bits to
   shift, instead of the numnber / 4 - made it easier to match with
   the manual.

Signed-off-by: Jamie Lenehan <lenehan@twibble.org>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
Jamie Lenehan 2006-12-06 12:05:02 +09:00 committed by Paul Mundt
parent fe9687dec0
commit ea0f8feaa0
10 changed files with 165 additions and 159 deletions

View File

@ -375,6 +375,9 @@ config CPU_HAS_MASKREG_IRQ
config CPU_HAS_INTC2_IRQ
bool
config CPU_HAS_IPR_IRQ
bool
config CPU_HAS_SR_RB
bool "CPU has SR.RB"
depends on CPU_SH3 || CPU_SH4

View File

@ -1,26 +1,30 @@
/*
* Setup for Titan
* arch/sh/boards/titan/setup.c - Setup for Titan
*
* Copyright (C) 2006 Jamie Lenehan
*
* 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/init.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/titan.h>
#include <asm/io.h>
extern void __init pcibios_init_platform(void);
static struct ipr_data titan_ipr_map[] = {
{ TITAN_IRQ_WAN, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY },
{ TITAN_IRQ_LAN, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY },
{ TITAN_IRQ_MPCIA, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY },
{ TITAN_IRQ_USB, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY },
/* IRQ, IPR idx, shift, prio */
{ TITAN_IRQ_WAN, 3, 12, 8 }, /* eth0 (WAN) */
{ TITAN_IRQ_LAN, 3, 8, 8 }, /* eth1 (LAN) */
{ TITAN_IRQ_MPCIA, 3, 4, 8 }, /* mPCI A (top) */
{ TITAN_IRQ_USB, 3, 0, 8 }, /* mPCI B (bottom), USB */
};
static void __init init_titan_irq(void)
{
/* enable individual interrupt mode for externals */
ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
ipr_irq_enable_irlm();
/* register ipr irqs */
make_ipr_irq(titan_ipr_map, ARRAY_SIZE(titan_ipr_map));
}
@ -47,6 +51,5 @@ struct sh_machine_vector mv_titan __initmv = {
.mv_ioport_map = titan_ioport_map,
.mv_init_irq = init_titan_irq,
.mv_init_pci = pcibios_init_platform,
};
ALIAS_MV(titan)

View File

@ -15,25 +15,21 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <linux/io.h>
#include <asm/titan.h>
#include "pci-sh4.h"
static char titan_irq_tab[] __initdata = {
TITAN_IRQ_WAN,
TITAN_IRQ_LAN,
TITAN_IRQ_MPCIA,
TITAN_IRQ_MPCIB,
TITAN_IRQ_USB,
};
int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = -1;
switch (slot) {
case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */
case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */
case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */
case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */
case 4: irq = TITAN_IRQ_USB; break; /* USB */
default:
printk(KERN_INFO "PCI: Bad IRQ mapping "
"request for slot %d\n", slot);
return -1;
}
int irq = titan_irq_tab[slot];
printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n",
slot, pin - 1 + 'A', irq);

View File

@ -1,8 +1,9 @@
#
# Makefile for the Linux/SuperH CPU-specifc IRQ handlers.
#
obj-y += ipr.o imask.o
obj-y += imask.o
obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o
obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o

View File

@ -25,17 +25,15 @@
static void disable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
int shift = p->shift*4;
/* Set the priority in IPR to 0 */
ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << shift)), p->addr);
ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
}
static void enable_ipr_irq(unsigned int irq)
{
struct ipr_data *p = get_irq_chip_data(irq);
int shift = p->shift*4;
/* Set priority in IPR back to original value */
ctrl_outw(ctrl_inw(p->addr) | (p->priority << shift), p->addr);
ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
}
static struct irq_chip ipr_irq_chip = {
@ -51,6 +49,10 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
for (i = 0; i < nr_irqs; i++) {
unsigned int irq = table[i].irq;
table[i].addr = map_ipridx_to_addr(table[i].ipr_idx);
/* could the IPR index be mapped, if not we ignore this */
if (table[i].addr == 0)
continue;
disable_irq_nosync(irq);
set_irq_chip_and_handler_name(irq, &ipr_irq_chip,
handle_level_irq, "level");
@ -60,99 +62,6 @@ void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs)
}
EXPORT_SYMBOL(make_ipr_irq);
/*
* XXX: Move this garbage in to the drivers, and kill off the ridiculous CPU
* subtype checks.
*/
static struct ipr_data sys_ipr_map[] = {
#ifndef CONFIG_CPU_SUBTYPE_SH7780
{ TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY },
{ TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY },
#ifdef RTC_IRQ
{ RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY },
#endif
#ifdef SCI_ERI_IRQ
{ SCI_ERI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
{ SCI_RXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
{ SCI_TXI_IRQ, SCI_IPR_ADDR, SCI_IPR_POS, SCI_PRIORITY },
#endif
#ifdef SCIF1_ERI_IRQ
{ SCIF1_ERI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
{ SCIF1_RXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
{ SCIF1_BRI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
{ SCIF1_TXI_IRQ, SCIF1_IPR_ADDR, SCIF1_IPR_POS, SCIF1_PRIORITY },
#endif
#ifdef SCIF2_ERI_IRQ
{ SCIF2_ERI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
{ SCIF2_RXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
{ SCIF2_BRI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
{ SCIF2_TXI_IRQ, SCIF2_IPR_ADDR, SCIF2_IPR_POS, SCIF2_PRIORITY },
#endif
#ifdef SCIF3_ERI_IRQ
{ SCIF3_ERI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
{ SCIF3_RXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
{ SCIF3_BRI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
{ SCIF3_TXI_IRQ, SCIF3_IPR_ADDR, SCIF3_IPR_POS, SCIF3_PRIORITY },
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7300)
{ SCIF0_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS, SCIF0_PRIORITY },
{ DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
{ DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY },
{ VIO_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY },
#endif
#ifdef SCIF_ERI_IRQ
{ SCIF_ERI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
{ SCIF_RXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
{ SCIF_BRI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
{ SCIF_TXI_IRQ, SCIF_IPR_ADDR, SCIF_IPR_POS, SCIF_PRIORITY },
#endif
#ifdef IRDA_ERI_IRQ
{ IRDA_ERI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
{ IRDA_RXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
{ IRDA_BRI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
{ IRDA_TXI_IRQ, IRDA_IPR_ADDR, IRDA_IPR_POS, IRDA_PRIORITY },
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
/*
* Initialize the Interrupt Controller (INTC)
* registers to their power on values
*/
/*
* Enable external irq (INTC IRQ mode).
* You should set corresponding bits of PFC to "00"
* to enable these interrupts.
*/
{ IRQ0_IRQ, IRQ0_IPR_ADDR, IRQ0_IPR_POS, IRQ0_PRIORITY },
{ IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY },
{ IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY },
{ IRQ3_IRQ, IRQ3_IPR_ADDR, IRQ3_IPR_POS, IRQ3_PRIORITY },
{ IRQ4_IRQ, IRQ4_IPR_ADDR, IRQ4_IPR_POS, IRQ4_PRIORITY },
{ IRQ5_IRQ, IRQ5_IPR_ADDR, IRQ5_IPR_POS, IRQ5_PRIORITY },
#endif
#endif
};
void __init init_IRQ(void)
{
make_ipr_irq(sys_ipr_map, ARRAY_SIZE(sys_ipr_map));
#ifdef CONFIG_CPU_HAS_PINT_IRQ
init_IRQ_pint();
#endif
#ifdef CONFIG_CPU_HAS_INTC2_IRQ
init_IRQ_intc2();
#endif
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq != NULL)
sh_mv.mv_init_irq();
irq_ctx_init(smp_processor_id());
}
#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
int ipr_irq_demux(int irq)
{

View File

@ -2,6 +2,7 @@
* SH7750/SH7751 Setup
*
* Copyright (C) 2006 Paul Mundt
* Copyright (C) 2006 Jamie Lenehan
*
* 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
@ -10,6 +11,7 @@
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <asm/sci.h>
static struct plat_sci_port sci_platform_data[] = {
@ -46,3 +48,71 @@ static int __init sh7750_devices_setup(void)
ARRAY_SIZE(sh7750_devices));
}
__initcall(sh7750_devices_setup);
static struct ipr_data sh7750_ipr_map[] = {
/* IRQ, IPR-idx, shift, priority */
{ 16, 0, 12, 2 }, /* TMU0 TUNI*/
{ 17, 0, 12, 2 }, /* TMU1 TUNI */
{ 18, 0, 4, 2 }, /* TMU2 TUNI */
{ 19, 0, 4, 2 }, /* TMU2 TIPCI */
{ 27, 1, 12, 2 }, /* WDT ITI */
{ 20, 0, 0, 2 }, /* RTC ATI (alarm) */
{ 21, 0, 0, 2 }, /* RTC PRI (period) */
{ 22, 0, 0, 2 }, /* RTC CUI (carry) */
{ 23, 1, 4, 3 }, /* SCI ERI */
{ 24, 1, 4, 3 }, /* SCI RXI */
{ 25, 1, 4, 3 }, /* SCI TXI */
{ 40, 2, 4, 3 }, /* SCIF ERI */
{ 41, 2, 4, 3 }, /* SCIF RXI */
{ 42, 2, 4, 3 }, /* SCIF BRI */
{ 43, 2, 4, 3 }, /* SCIF TXI */
{ 34, 2, 8, 7 }, /* DMAC DMTE0 */
{ 35, 2, 8, 7 }, /* DMAC DMTE1 */
{ 36, 2, 8, 7 }, /* DMAC DMTE2 */
{ 37, 2, 8, 7 }, /* DMAC DMTE3 */
{ 28, 2, 8, 7 }, /* DMAC DMAE */
};
static struct ipr_data sh7751_ipr_map[] = {
{ 44, 2, 8, 7 }, /* DMAC DMTE4 */
{ 45, 2, 8, 7 }, /* DMAC DMTE5 */
{ 46, 2, 8, 7 }, /* DMAC DMTE6 */
{ 47, 2, 8, 7 }, /* DMAC DMTE7 */
/* The following use INTC_INPRI00 for masking, which is a 32-bit
register, not a 16-bit register like the IPRx registers, so it
would need special support */
/*{ 72, INTPRI00, 8, ? },*/ /* TMU3 TUNI */
/*{ 76, INTPRI00, 12, ? },*/ /* TMU4 TUNI */
};
static unsigned long ipr_offsets[] = {
0xffd00004UL, /* 0: IPRA */
0xffd00008UL, /* 1: IPRB */
0xffd0000cUL, /* 2: IPRC */
0xffd00010UL, /* 3: IPRD */
};
/* given the IPR index return the address of the IPR register */
unsigned int map_ipridx_to_addr(int idx)
{
if (idx >= ARRAY_SIZE(ipr_offsets))
return 0;
return ipr_offsets[idx];
}
#define INTC_ICR 0xffd00000UL
#define INTC_ICR_IRLM (1<<7)
/* enable individual interrupt mode for external interupts */
void ipr_irq_enable_irlm(void)
{
ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
}
void __init init_IRQ_ipr()
{
make_ipr_irq(sh7750_ipr_map, ARRAY_SIZE(sh7750_ipr_map));
#ifdef CONFIG_CPU_SUBTYPE_SH7751
make_ipr_irq(sh7751_ipr_map, ARRAY_SIZE(sh7751_ipr_map));
#endif
}

View File

@ -12,7 +12,7 @@
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
#include <linux/io.h>
#include <asm/irq.h>
#include <linux/irq.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#include <asm/thread_info.h>
@ -112,7 +112,7 @@ asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
#endif
#ifdef CONFIG_CPU_HAS_INTEVT
irq = (ctrl_inl(INTEVT) >> 5) - 16;
irq = evt2irq(ctrl_inl(INTEVT));
#else
irq = r4;
#endif
@ -261,3 +261,24 @@ asmlinkage void do_softirq(void)
}
EXPORT_SYMBOL(do_softirq);
#endif
void __init init_IRQ(void)
{
#ifdef CONFIG_CPU_HAS_PINT_IRQ
init_IRQ_pint();
#endif
#ifdef CONFIG_CPU_HAS_INTC2_IRQ
init_IRQ_intc2();
#endif
#ifdef CONFIG_CPU_HAS_IPR_IRQ
init_IRQ_ipr();
#endif
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq)
sh_mv.mv_init_irq();
irq_ctx_init(smp_processor_id());
}

View File

@ -104,6 +104,7 @@ comment "SH-4 Processor Support"
config CPU_SUBTYPE_SH7750
bool "Support SH7750 processor"
select CPU_SH4
select CPU_HAS_IPR_IRQ
help
Select SH7750 if you have a 200 Mhz SH-4 HD6417750 CPU.
@ -119,15 +120,18 @@ config CPU_SUBTYPE_SH7750R
bool "Support SH7750R processor"
select CPU_SH4
select CPU_SUBTYPE_SH7750
select CPU_HAS_IPR_IRQ
config CPU_SUBTYPE_SH7750S
bool "Support SH7750S processor"
select CPU_SH4
select CPU_SUBTYPE_SH7750
select CPU_HAS_IPR_IRQ
config CPU_SUBTYPE_SH7751
bool "Support SH7751 processor"
select CPU_SH4
select CPU_HAS_IPR_IRQ
help
Select SH7751 if you have a 166 Mhz SH-4 HD6417751 CPU,
or if you have a HD6417751R CPU.
@ -136,6 +140,7 @@ config CPU_SUBTYPE_SH7751R
bool "Support SH7751R processor"
select CPU_SH4
select CPU_SUBTYPE_SH7751
select CPU_HAS_IPR_IRQ
config CPU_SUBTYPE_SH7760
bool "Support SH7760 processor"

View File

@ -92,6 +92,12 @@
/* NR_IRQS. 1+2+3 */
#define NR_IRQS (ONCHIP_NR_IRQS + PINT_NR_IRQS + OFFCHIP_NR_IRQS)
/*
* Convert back and forth between INTEVT and IRQ values.
*/
#define evt2irq(evt) (((evt) >> 5) - 16)
#define irq2evt(irq) (((irq) + 16) << 5)
/*
* Simple Mask Register Support
*/
@ -103,18 +109,36 @@ extern unsigned short *irq_mask_register;
*/
void init_IRQ_pint(void);
/*
* The shift value is now the number of bits to shift, not the number of
* bits/4. This is to make it easier to read the value directly from the
* datasheets. The IPR address, addr, will be set from ipr_idx via the
* map_ipridx_to_addr function.
*/
struct ipr_data {
unsigned int irq;
unsigned int addr; /* Address of Interrupt Priority Register */
int shift; /* Shifts of the 16-bit data */
int ipr_idx; /* Index for the IPR registered */
int shift; /* Number of bits to shift the data */
int priority; /* The priority */
unsigned int addr; /* Address of Interrupt Priority Register */
};
/*
* Given an IPR IDX, map the value to an IPR register address.
*/
unsigned int map_ipridx_to_addr(int idx);
/*
* Enable individual interrupt mode for external IPR IRQs.
*/
void ipr_irq_enable_irlm(void);
/*
* Function for "on chip support modules".
*/
extern void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs);
extern void make_imask_irq(unsigned int irq);
void make_ipr_irq(struct ipr_data *table, unsigned int nr_irqs);
void make_imask_irq(unsigned int irq);
void init_IRQ_ipr(void);
struct intc2_data {
unsigned short irq;

View File

@ -1,9 +1,8 @@
/*
* Platform defintions for Titan
*/
#ifndef _ASM_SH_TITAN_TITAN_H
#define _ASM_SH_TITAN_TITAN_H
#ifndef _ASM_SH_TITAN_H
#define _ASM_SH_TITAN_H
#define __IO_PREFIX titan
#include <asm/io_generic.h>
@ -15,29 +14,4 @@
#define TITAN_IRQ_MPCIB 11 /* mPCI B */
#define TITAN_IRQ_USB 11 /* USB */
/*
* The external interrupt lines, these take up ints 0 - 15 inclusive
* depending on the priority for the interrupt. In fact the priority
* is the interrupt :-)
*/
#define IRL0_IRQ 0
#define IRL0_IPR_ADDR INTC_IPRD
#define IRL0_IPR_POS 3
#define IRL0_PRIORITY 8
#define IRL1_IRQ 1
#define IRL1_IPR_ADDR INTC_IPRD
#define IRL1_IPR_POS 2
#define IRL1_PRIORITY 8
#define IRL2_IRQ 2
#define IRL2_IPR_ADDR INTC_IPRD
#define IRL2_IPR_POS 1
#define IRL2_PRIORITY 8
#define IRL3_IRQ 3
#define IRL3_IPR_ADDR INTC_IPRD
#define IRL3_IPR_POS 0
#define IRL3_PRIORITY 8
#endif
#endif /* __ASM_SH_TITAN_H */