~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/sh/boards/mach-dreamcast/irq.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arch/sh/boards/dreamcast/irq.c
 
3
 *
 
4
 * Holly IRQ support for the Sega Dreamcast.
 
5
 *
 
6
 * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org>
 
7
 *
 
8
 * This file is part of the LinuxDC project (www.linuxdc.org)
 
9
 * Released under the terms of the GNU GPL v2.0
 
10
 */
 
11
 
 
12
#include <linux/irq.h>
 
13
#include <linux/io.h>
 
14
#include <asm/irq.h>
 
15
#include <mach/sysasic.h>
 
16
 
 
17
/*
 
18
 * Dreamcast System ASIC Hardware Events -
 
19
 *
 
20
 * The Dreamcast's System ASIC (a.k.a. Holly) is responsible for receiving
 
21
 * hardware events from system peripherals and triggering an SH7750 IRQ.
 
22
 * Hardware events can trigger IRQs 13, 11, or 9 depending on which bits are
 
23
 * set in the Event Mask Registers (EMRs).  When a hardware event is
 
24
 * triggered, its corresponding bit in the Event Status Registers (ESRs)
 
25
 * is set, and that bit should be rewritten to the ESR to acknowledge that
 
26
 * event.
 
27
 *
 
28
 * There are three 32-bit ESRs located at 0xa05f6900 - 0xa05f6908.  Event
 
29
 * types can be found in arch/sh/include/mach-dreamcast/mach/sysasic.h.
 
30
 * There are three groups of EMRs that parallel the ESRs.  Each EMR group
 
31
 * corresponds to an IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13,
 
32
 * 0xa05f6920 - 0xa05f6928 triggers IRQ 11, and 0xa05f6930 - 0xa05f6938
 
33
 * triggers IRQ 9.
 
34
 *
 
35
 * In the kernel, these events are mapped to virtual IRQs so that drivers can
 
36
 * respond to them as they would a normal interrupt.  In order to keep this
 
37
 * mapping simple, the events are mapped as:
 
38
 *
 
39
 * 6900/6910 - Events  0-31, IRQ 13
 
40
 * 6904/6924 - Events 32-63, IRQ 11
 
41
 * 6908/6938 - Events 64-95, IRQ  9
 
42
 *
 
43
 */
 
44
 
 
45
#define ESR_BASE 0x005f6900    /* Base event status register */
 
46
#define EMR_BASE 0x005f6910    /* Base event mask register */
 
47
 
 
48
/*
 
49
 * Helps us determine the EMR group that this event belongs to: 0 = 0x6910,
 
50
 * 1 = 0x6920, 2 = 0x6930; also determine the event offset.
 
51
 */
 
52
#define LEVEL(event) (((event) - HW_EVENT_IRQ_BASE) / 32)
 
53
 
 
54
/* Return the hardware event's bit position within the EMR/ESR */
 
55
#define EVENT_BIT(event) (((event) - HW_EVENT_IRQ_BASE) & 31)
 
56
 
 
57
/*
 
58
 * For each of these *_irq routines, the IRQ passed in is the virtual IRQ
 
59
 * (logically mapped to the corresponding bit for the hardware event).
 
60
 */
 
61
 
 
62
/* Disable the hardware event by masking its bit in its EMR */
 
63
static inline void disable_systemasic_irq(struct irq_data *data)
 
64
{
 
65
        unsigned int irq = data->irq;
 
66
        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
 
67
        __u32 mask;
 
68
 
 
69
        mask = inl(emr);
 
70
        mask &= ~(1 << EVENT_BIT(irq));
 
71
        outl(mask, emr);
 
72
}
 
73
 
 
74
/* Enable the hardware event by setting its bit in its EMR */
 
75
static inline void enable_systemasic_irq(struct irq_data *data)
 
76
{
 
77
        unsigned int irq = data->irq;
 
78
        __u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
 
79
        __u32 mask;
 
80
 
 
81
        mask = inl(emr);
 
82
        mask |= (1 << EVENT_BIT(irq));
 
83
        outl(mask, emr);
 
84
}
 
85
 
 
86
/* Acknowledge a hardware event by writing its bit back to its ESR */
 
87
static void mask_ack_systemasic_irq(struct irq_data *data)
 
88
{
 
89
        unsigned int irq = data->irq;
 
90
        __u32 esr = ESR_BASE + (LEVEL(irq) << 2);
 
91
        disable_systemasic_irq(data);
 
92
        outl((1 << EVENT_BIT(irq)), esr);
 
93
}
 
94
 
 
95
struct irq_chip systemasic_int = {
 
96
        .name           = "System ASIC",
 
97
        .irq_mask       = disable_systemasic_irq,
 
98
        .irq_mask_ack   = mask_ack_systemasic_irq,
 
99
        .irq_unmask     = enable_systemasic_irq,
 
100
};
 
101
 
 
102
/*
 
103
 * Map the hardware event indicated by the processor IRQ to a virtual IRQ.
 
104
 */
 
105
int systemasic_irq_demux(int irq)
 
106
{
 
107
        __u32 emr, esr, status, level;
 
108
        __u32 j, bit;
 
109
 
 
110
        switch (irq) {
 
111
        case 13:
 
112
                level = 0;
 
113
                break;
 
114
        case 11:
 
115
                level = 1;
 
116
                break;
 
117
        case  9:
 
118
                level = 2;
 
119
                break;
 
120
        default:
 
121
                return irq;
 
122
        }
 
123
        emr = EMR_BASE + (level << 4) + (level << 2);
 
124
        esr = ESR_BASE + (level << 2);
 
125
 
 
126
        /* Mask the ESR to filter any spurious, unwanted interrupts */
 
127
        status = inl(esr);
 
128
        status &= inl(emr);
 
129
 
 
130
        /* Now scan and find the first set bit as the event to map */
 
131
        for (bit = 1, j = 0; j < 32; bit <<= 1, j++) {
 
132
                if (status & bit) {
 
133
                        irq = HW_EVENT_IRQ_BASE + j + (level << 5);
 
134
                        return irq;
 
135
                }
 
136
        }
 
137
 
 
138
        /* Not reached */
 
139
        return irq;
 
140
}
 
141
 
 
142
void systemasic_irq_init(void)
 
143
{
 
144
        int i, nid = cpu_to_node(boot_cpu_data);
 
145
 
 
146
        /* Assign all virtual IRQs to the System ASIC int. handler */
 
147
        for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) {
 
148
                unsigned int irq;
 
149
 
 
150
                irq = create_irq_nr(i, nid);
 
151
                if (unlikely(irq == 0)) {
 
152
                        pr_err("%s: failed hooking irq %d for systemasic\n",
 
153
                               __func__, i);
 
154
                        return;
 
155
                }
 
156
 
 
157
                if (unlikely(irq != i)) {
 
158
                        pr_err("%s: got irq %d but wanted %d, bailing.\n",
 
159
                               __func__, irq, i);
 
160
                        destroy_irq(irq);
 
161
                        return;
 
162
                }
 
163
 
 
164
                irq_set_chip_and_handler(i, &systemasic_int, handle_level_irq);
 
165
        }
 
166
}