1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <ifxmips_irq.h>
#include "mps.h"
#include "mps-irq.h"
#define MPS_REG_AD0_IRQ_BASE 0x40
#define MPS_REG_AD1_IRQ_BASE 0x44
#define MPS_REG_AD_IRQ_STATUS 0x00
#define MPS_REG_AD_IRQ_SET 0x08
#define MPS_REG_AD_IRQ_CLEAR 0x10
#define MPS_REG_AD_IRQ_ENABLE 0x18
struct mps_irq_desc
{
void __iomem *base;
unsigned int irq_base;
};
static inline unsigned int mps_irq_bit(struct mps_irq_desc *mps_desc, int irq)
{
return BIT(irq - mps_desc->irq_base);
}
static void mps_irq_ack(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
__raw_writel(mps_irq_bit(mps_desc, irq),
mps_desc->base + MPS_REG_AD_IRQ_CLEAR);
}
static void mps_irq_mask(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
uint32_t mask;
mask = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
mask &= ~mps_irq_bit(mps_desc, irq);
__raw_writel(mask, mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
}
static void mps_irq_unmask(unsigned int irq)
{
struct mps_irq_desc *mps_desc = get_irq_chip_data(irq);
uint32_t mask;
mask = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
mask |= mps_irq_bit(mps_desc, irq) | 0xffff;
__raw_writel(mask, mps_desc->base + MPS_REG_AD_IRQ_ENABLE);
}
static struct irq_chip mps_irq_chip = {
.name = "mps",
.ack = mps_irq_ack,
.mask = mps_irq_mask,
.unmask = mps_irq_unmask,
};
static void mps_irq_demux_handler(unsigned int irq, struct irq_desc *desc)
{
struct mps_irq_desc *mps_desc = get_irq_data(irq);
uint32_t val;
int mps_irq;
desc->chip->mask(irq);
val = __raw_readl(mps_desc->base + MPS_REG_AD_IRQ_STATUS);
mps_irq = ffs(val);
/* printk("irq: %d %x\n", mps_irq, val);*/
if (mps_irq > 16)
printk("PANIC!\n");
if (mps_irq)
generic_handle_irq(mps_irq + mps_desc->irq_base - 1);
desc->chip->ack(irq);
desc->chip->unmask(irq);
}
#if 0
static const uint32_t ring_msg[] = {
0x01010004, 0x00030000,
};
static irqreturn_t mps_irq_ad0(int irq, void *devid)
{
struct mps *mps = devid;
uint32_t val;
val = __raw_readl(mps->base + MPS_REG_AD0_IRQ_STATUS);
printk("WOHO ein IRQ: %x\n", val);
__raw_writel(val, mps->base + MPS_REG_AD0_IRQ_CLEAR);
if (val & BIT(MPS_IRQ_DOWNLOAD_DONE))
complete(&mps->init_completion);
if (val & BIT(MPS_IRQ_EVENT))
mps_fifo_in(&mps->mbox_cmd.downstream, ring_msg, ARRAY_SIZE(ring_msg));
return IRQ_HANDLED;
}
#endif
#define MPS_NUM_AD_IRQS 32
struct mps_irq_desc mps_irq_descs[2];
int mps_irq_init(struct mps *mps)
{
int ret = 0;
int irq;
mps_irq_descs[0].base = mps->base + MPS_REG_AD0_IRQ_BASE;
mps_irq_descs[0].irq_base = mps->irq_base;
mps_irq_descs[1].base = mps->base + MPS_REG_AD1_IRQ_BASE;
mps_irq_descs[1].irq_base = mps->irq_base + 16;
set_irq_data(mps->irq_ad0, &mps_irq_descs[0]);
set_irq_chained_handler(mps->irq_ad0, mps_irq_demux_handler);
set_irq_data(mps->irq_ad1, &mps_irq_descs[1]);
set_irq_chained_handler(mps->irq_ad1, mps_irq_demux_handler);
/*
ret = request_irq(mps->irq_ad0, mps_irq_demux_handler, IRQF_DISABLED,
"mps ad0", &mps_irq_descs[0]);
ret = request_irq(mps->irq_ad1, mps_irq_demux_handler, IRQF_DISABLED,
"mps ad0", &mps_irq_descs[1]);
*/
for (irq = 0; irq < MPS_NUM_AD_IRQS; ++irq) {
set_irq_chip_data(irq + mps->irq_base, &mps_irq_descs[irq / 16]);
set_irq_chip_and_handler(irq + mps->irq_base, &mps_irq_chip, handle_level_irq);
}
/*
res = request_irq(INT_NUM_IM4_IRL18, mps_irq_ad0, IRQF_DISABLED,
"mps ad0", mps);
irqs = BIT(MPS_IRQ_CMD_UPSTREAM) | BIT(MPS_IRQ_DATA_UPSTREAM)
| BIT(MPS_IRQ_DOWNLOAD_DONE) | BIT(MPS_IRQ_EVENT) | BIT(MPS_IRQ_CMD_ERROR);
__raw_writel(irqs, mps->base + MPS_REG_AD0_IRQ_ENA);
*/
return ret;
}
void mps_irq_exit(struct mps *mps)
{
free_irq(INT_NUM_IM4_IRL18, mps);
}
|