Browse Source
Signed-off-by: Evgeny Voevodin <e.voevodin@samsung.com> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>stable-1.1
committed by
Peter Maydell
4 changed files with 1010 additions and 0 deletions
@ -0,0 +1,82 @@ |
|||
/*
|
|||
* Samsung exynos4210 SoC emulation |
|||
* |
|||
* Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. |
|||
* Maksim Kozlov <m.kozlov@samsung.com> |
|||
* Evgeny Voevodin <e.voevodin@samsung.com> |
|||
* Igor Mitsyanko <i.mitsyanko@samsung.com> |
|||
* |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify it |
|||
* under the terms of the GNU General Public License as published by the |
|||
* Free Software Foundation; either version 2 of the License, or |
|||
* (at your option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, but WITHOUT |
|||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|||
* for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
* |
|||
*/ |
|||
|
|||
|
|||
#ifndef EXYNOS4210_H_ |
|||
#define EXYNOS4210_H_ |
|||
|
|||
#include "qemu-common.h" |
|||
#include "memory.h" |
|||
|
|||
#define EXYNOS4210_NCPUS 2 |
|||
|
|||
/*
|
|||
* exynos4210 IRQ subsystem stub definitions. |
|||
*/ |
|||
#define EXYNOS4210_IRQ_GATE_NINPUTS 8 |
|||
|
|||
#define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ 64 |
|||
#define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ 16 |
|||
#define EXYNOS4210_MAX_INT_COMBINER_IN_IRQ \ |
|||
(EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ * 8) |
|||
#define EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ \ |
|||
(EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ * 8) |
|||
|
|||
#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp)*8 + (bit)) |
|||
#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8) |
|||
#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \ |
|||
((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq)) |
|||
|
|||
/* IRQs number for external and internal GIC */ |
|||
#define EXYNOS4210_EXT_GIC_NIRQ (160-32) |
|||
#define EXYNOS4210_INT_GIC_NIRQ 64 |
|||
|
|||
typedef struct Exynos4210Irq { |
|||
qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; |
|||
qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ]; |
|||
qemu_irq int_gic_irq[EXYNOS4210_INT_GIC_NIRQ]; |
|||
qemu_irq ext_gic_irq[EXYNOS4210_EXT_GIC_NIRQ]; |
|||
qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ]; |
|||
} Exynos4210Irq; |
|||
|
|||
/* Initialize exynos4210 IRQ subsystem stub */ |
|||
qemu_irq *exynos4210_init_irq(Exynos4210Irq *env); |
|||
|
|||
/* Initialize board IRQs.
|
|||
* These IRQs contain splitted Int/External Combiner and External Gic IRQs */ |
|||
void exynos4210_init_board_irqs(Exynos4210Irq *s); |
|||
|
|||
/* Get IRQ number from exynos4210 IRQ subsystem stub.
|
|||
* To identify IRQ source use internal combiner group and bit number |
|||
* grp - group number |
|||
* bit - bit number inside group */ |
|||
uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit); |
|||
|
|||
/*
|
|||
* Get Combiner input GPIO into irqs structure |
|||
*/ |
|||
void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, |
|||
int ext); |
|||
|
|||
#endif /* EXYNOS4210_H_ */ |
|||
@ -0,0 +1,469 @@ |
|||
/*
|
|||
* Samsung exynos4210 Interrupt Combiner |
|||
* |
|||
* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. |
|||
* All rights reserved. |
|||
* |
|||
* Evgeny Voevodin <e.voevodin@samsung.com> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify it |
|||
* under the terms of the GNU General Public License as published by the |
|||
* Free Software Foundation; either version 2 of the License, or (at your |
|||
* option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* See the GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
/*
|
|||
* Exynos4210 Combiner represents an OR gate for SOC's IRQ lines. It combines |
|||
* IRQ sources into groups and provides signal output to GIC from each group. It |
|||
* is driven by common mask and enable/disable logic. Take a note that not all |
|||
* IRQs are passed to GIC through Combiner. |
|||
*/ |
|||
|
|||
#include "sysbus.h" |
|||
|
|||
#include "exynos4210.h" |
|||
|
|||
//#define DEBUG_COMBINER
|
|||
|
|||
#ifdef DEBUG_COMBINER |
|||
#define DPRINTF(fmt, ...) \ |
|||
do { fprintf(stdout, "COMBINER: [%s:%d] " fmt, __func__ , __LINE__, \ |
|||
## __VA_ARGS__); } while (0) |
|||
#else |
|||
#define DPRINTF(fmt, ...) do {} while (0) |
|||
#endif |
|||
|
|||
#define IIC_NGRP 64 /* Internal Interrupt Combiner |
|||
Groups number */ |
|||
#define IIC_NIRQ (IIC_NGRP * 8)/* Internal Interrupt Combiner |
|||
Interrupts number */ |
|||
#define IIC_REGION_SIZE 0x108 /* Size of memory mapped region */ |
|||
#define IIC_REGSET_SIZE 0x41 |
|||
|
|||
/*
|
|||
* State for each output signal of internal combiner |
|||
*/ |
|||
typedef struct CombinerGroupState { |
|||
uint8_t src_mask; /* 1 - source enabled, 0 - disabled */ |
|||
uint8_t src_pending; /* Pending source interrupts before masking */ |
|||
} CombinerGroupState; |
|||
|
|||
typedef struct Exynos4210CombinerState { |
|||
SysBusDevice busdev; |
|||
MemoryRegion iomem; |
|||
|
|||
struct CombinerGroupState group[IIC_NGRP]; |
|||
uint32_t reg_set[IIC_REGSET_SIZE]; |
|||
uint32_t icipsr[2]; |
|||
uint32_t external; /* 1 means that this combiner is external */ |
|||
|
|||
qemu_irq output_irq[IIC_NGRP]; |
|||
} Exynos4210CombinerState; |
|||
|
|||
static const VMStateDescription vmstate_exynos4210_combiner_group_state = { |
|||
.name = "exynos4210.combiner.groupstate", |
|||
.version_id = 1, |
|||
.minimum_version_id = 1, |
|||
.minimum_version_id_old = 1, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_UINT8(src_mask, CombinerGroupState), |
|||
VMSTATE_UINT8(src_pending, CombinerGroupState), |
|||
VMSTATE_END_OF_LIST() |
|||
} |
|||
}; |
|||
|
|||
static const VMStateDescription vmstate_exynos4210_combiner = { |
|||
.name = "exynos4210.combiner", |
|||
.version_id = 1, |
|||
.minimum_version_id = 1, |
|||
.minimum_version_id_old = 1, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_STRUCT_ARRAY(group, Exynos4210CombinerState, IIC_NGRP, 0, |
|||
vmstate_exynos4210_combiner_group_state, CombinerGroupState), |
|||
VMSTATE_UINT32_ARRAY(reg_set, Exynos4210CombinerState, |
|||
IIC_REGSET_SIZE), |
|||
VMSTATE_UINT32_ARRAY(icipsr, Exynos4210CombinerState, 2), |
|||
VMSTATE_UINT32(external, Exynos4210CombinerState), |
|||
VMSTATE_END_OF_LIST() |
|||
} |
|||
}; |
|||
|
|||
/*
|
|||
* Get Combiner input GPIO into irqs structure |
|||
*/ |
|||
void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev, |
|||
int ext) |
|||
{ |
|||
int n; |
|||
int bit; |
|||
int max; |
|||
qemu_irq *irq; |
|||
|
|||
max = ext ? EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ : |
|||
EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; |
|||
irq = ext ? irqs->ext_combiner_irq : irqs->int_combiner_irq; |
|||
|
|||
/*
|
|||
* Some IRQs of Int/External Combiner are going to two Combiners groups, |
|||
* so let split them. |
|||
*/ |
|||
for (n = 0; n < max; n++) { |
|||
|
|||
bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); |
|||
|
|||
switch (n) { |
|||
/* MDNIE_LCD1 INTG1 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 0) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 3): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(0, bit + 4)]); |
|||
continue; |
|||
|
|||
/* TMU INTG3 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(3, 4): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(2, bit)]); |
|||
continue; |
|||
|
|||
/* LCD1 INTG12 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 0) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 3): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(11, bit + 4)]); |
|||
continue; |
|||
|
|||
/* Multi-Core Timer INTG12 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 8): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); |
|||
continue; |
|||
|
|||
/* Multi-Core Timer INTG35 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 4) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(35, 8): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); |
|||
continue; |
|||
|
|||
/* Multi-Core Timer INTG51 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 4) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(51, 8): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); |
|||
continue; |
|||
|
|||
/* Multi-Core Timer INTG53 */ |
|||
case EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 4) ... |
|||
EXYNOS4210_COMBINER_GET_IRQ_NUM(53, 8): |
|||
irq[n] = qemu_irq_split(qdev_get_gpio_in(dev, n), |
|||
irq[EXYNOS4210_COMBINER_GET_IRQ_NUM(1, bit + 4)]); |
|||
continue; |
|||
} |
|||
|
|||
irq[n] = qdev_get_gpio_in(dev, n); |
|||
} |
|||
} |
|||
|
|||
static uint64_t |
|||
exynos4210_combiner_read(void *opaque, target_phys_addr_t offset, unsigned size) |
|||
{ |
|||
struct Exynos4210CombinerState *s = |
|||
(struct Exynos4210CombinerState *)opaque; |
|||
uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4 and
|
|||
get a start of corresponding group quad */ |
|||
uint32_t grp_quad_base_n; /* Base of group quad */ |
|||
uint32_t reg_n; /* Register number inside the quad */ |
|||
uint32_t val; |
|||
|
|||
if (s->external && (offset > 0x3c && offset != 0x100)) { |
|||
hw_error("exynos4210.combiner: unallowed read access at offset 0x" |
|||
TARGET_FMT_plx "\n", offset); |
|||
} |
|||
|
|||
req_quad_base_n = offset >> 4; |
|||
grp_quad_base_n = req_quad_base_n << 2; |
|||
reg_n = (offset - (req_quad_base_n << 4)) >> 2; |
|||
|
|||
if (req_quad_base_n >= IIC_NGRP) { |
|||
/* Read of ICIPSR register */ |
|||
return s->icipsr[reg_n]; |
|||
} |
|||
|
|||
val = 0; |
|||
|
|||
switch (reg_n) { |
|||
/* IISTR */ |
|||
case 2: |
|||
val |= s->group[grp_quad_base_n].src_pending; |
|||
val |= s->group[grp_quad_base_n + 1].src_pending << 8; |
|||
val |= s->group[grp_quad_base_n + 2].src_pending << 16; |
|||
val |= s->group[grp_quad_base_n + 3].src_pending << 24; |
|||
break; |
|||
/* IIMSR */ |
|||
case 3: |
|||
val |= s->group[grp_quad_base_n].src_mask & |
|||
s->group[grp_quad_base_n].src_pending; |
|||
val |= (s->group[grp_quad_base_n + 1].src_mask & |
|||
s->group[grp_quad_base_n + 1].src_pending) << 8; |
|||
val |= (s->group[grp_quad_base_n + 2].src_mask & |
|||
s->group[grp_quad_base_n + 2].src_pending) << 16; |
|||
val |= (s->group[grp_quad_base_n + 3].src_mask & |
|||
s->group[grp_quad_base_n + 3].src_pending) << 24; |
|||
break; |
|||
default: |
|||
if (offset >> 2 >= IIC_REGSET_SIZE) { |
|||
hw_error("exynos4210.combiner: overflow of reg_set by 0x" |
|||
TARGET_FMT_plx "offset\n", offset); |
|||
} |
|||
val = s->reg_set[offset >> 2]; |
|||
return 0; |
|||
} |
|||
return val; |
|||
} |
|||
|
|||
static void exynos4210_combiner_update(void *opaque, uint8_t group_n) |
|||
{ |
|||
struct Exynos4210CombinerState *s = |
|||
(struct Exynos4210CombinerState *)opaque; |
|||
|
|||
/* Send interrupt if needed */ |
|||
if (s->group[group_n].src_mask & s->group[group_n].src_pending) { |
|||
#ifdef DEBUG_COMBINER |
|||
if (group_n != 26) { |
|||
/* skip uart */ |
|||
DPRINTF("%s raise IRQ[%d]\n", s->external ? "EXT" : "INT", group_n); |
|||
} |
|||
#endif |
|||
|
|||
/* Set Combiner interrupt pending status after masking */ |
|||
if (group_n >= 32) { |
|||
s->icipsr[1] |= 1 << (group_n - 32); |
|||
} else { |
|||
s->icipsr[0] |= 1 << group_n; |
|||
} |
|||
|
|||
qemu_irq_raise(s->output_irq[group_n]); |
|||
} else { |
|||
#ifdef DEBUG_COMBINER |
|||
if (group_n != 26) { |
|||
/* skip uart */ |
|||
DPRINTF("%s lower IRQ[%d]\n", s->external ? "EXT" : "INT", group_n); |
|||
} |
|||
#endif |
|||
|
|||
/* Set Combiner interrupt pending status after masking */ |
|||
if (group_n >= 32) { |
|||
s->icipsr[1] &= ~(1 << (group_n - 32)); |
|||
} else { |
|||
s->icipsr[0] &= ~(1 << group_n); |
|||
} |
|||
|
|||
qemu_irq_lower(s->output_irq[group_n]); |
|||
} |
|||
} |
|||
|
|||
static void exynos4210_combiner_write(void *opaque, target_phys_addr_t offset, |
|||
uint64_t val, unsigned size) |
|||
{ |
|||
struct Exynos4210CombinerState *s = |
|||
(struct Exynos4210CombinerState *)opaque; |
|||
uint32_t req_quad_base_n; /* Base of registers quad. Multiply it by 4 and
|
|||
get a start of corresponding group quad */ |
|||
uint32_t grp_quad_base_n; /* Base of group quad */ |
|||
uint32_t reg_n; /* Register number inside the quad */ |
|||
|
|||
if (s->external && (offset > 0x3c && offset != 0x100)) { |
|||
hw_error("exynos4210.combiner: unallowed write access at offset 0x" |
|||
TARGET_FMT_plx "\n", offset); |
|||
} |
|||
|
|||
req_quad_base_n = offset >> 4; |
|||
grp_quad_base_n = req_quad_base_n << 2; |
|||
reg_n = (offset - (req_quad_base_n << 4)) >> 2; |
|||
|
|||
if (req_quad_base_n >= IIC_NGRP) { |
|||
hw_error("exynos4210.combiner: unallowed write access at offset 0x" |
|||
TARGET_FMT_plx "\n", offset); |
|||
return; |
|||
} |
|||
|
|||
if (reg_n > 1) { |
|||
hw_error("exynos4210.combiner: unallowed write access at offset 0x" |
|||
TARGET_FMT_plx "\n", offset); |
|||
return; |
|||
} |
|||
|
|||
if (offset >> 2 >= IIC_REGSET_SIZE) { |
|||
hw_error("exynos4210.combiner: overflow of reg_set by 0x" |
|||
TARGET_FMT_plx "offset\n", offset); |
|||
} |
|||
s->reg_set[offset >> 2] = val; |
|||
|
|||
switch (reg_n) { |
|||
/* IIESR */ |
|||
case 0: |
|||
/* FIXME: what if irq is pending, allowed by mask, and we allow it
|
|||
* again. Interrupt will rise again! */ |
|||
|
|||
DPRINTF("%s enable IRQ for groups %d, %d, %d, %d\n", |
|||
s->external ? "EXT" : "INT", |
|||
grp_quad_base_n, |
|||
grp_quad_base_n + 1, |
|||
grp_quad_base_n + 2, |
|||
grp_quad_base_n + 3); |
|||
|
|||
/* Enable interrupt sources */ |
|||
s->group[grp_quad_base_n].src_mask |= val & 0xFF; |
|||
s->group[grp_quad_base_n + 1].src_mask |= (val & 0xFF00) >> 8; |
|||
s->group[grp_quad_base_n + 2].src_mask |= (val & 0xFF0000) >> 16; |
|||
s->group[grp_quad_base_n + 3].src_mask |= (val & 0xFF000000) >> 24; |
|||
|
|||
exynos4210_combiner_update(s, grp_quad_base_n); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 1); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 2); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 3); |
|||
break; |
|||
/* IIECR */ |
|||
case 1: |
|||
DPRINTF("%s disable IRQ for groups %d, %d, %d, %d\n", |
|||
s->external ? "EXT" : "INT", |
|||
grp_quad_base_n, |
|||
grp_quad_base_n + 1, |
|||
grp_quad_base_n + 2, |
|||
grp_quad_base_n + 3); |
|||
|
|||
/* Disable interrupt sources */ |
|||
s->group[grp_quad_base_n].src_mask &= ~(val & 0xFF); |
|||
s->group[grp_quad_base_n + 1].src_mask &= ~((val & 0xFF00) >> 8); |
|||
s->group[grp_quad_base_n + 2].src_mask &= ~((val & 0xFF0000) >> 16); |
|||
s->group[grp_quad_base_n + 3].src_mask &= ~((val & 0xFF000000) >> 24); |
|||
|
|||
exynos4210_combiner_update(s, grp_quad_base_n); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 1); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 2); |
|||
exynos4210_combiner_update(s, grp_quad_base_n + 3); |
|||
break; |
|||
default: |
|||
hw_error("exynos4210.combiner: unallowed write access at offset 0x" |
|||
TARGET_FMT_plx "\n", offset); |
|||
break; |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
/* Get combiner group and bit from irq number */ |
|||
static uint8_t get_combiner_group_and_bit(int irq, uint8_t *bit) |
|||
{ |
|||
*bit = irq - ((irq >> 3) << 3); |
|||
return irq >> 3; |
|||
} |
|||
|
|||
/* Process a change in an external IRQ input. */ |
|||
static void exynos4210_combiner_handler(void *opaque, int irq, int level) |
|||
{ |
|||
struct Exynos4210CombinerState *s = |
|||
(struct Exynos4210CombinerState *)opaque; |
|||
uint8_t bit_n, group_n; |
|||
|
|||
group_n = get_combiner_group_and_bit(irq, &bit_n); |
|||
|
|||
if (s->external && group_n >= EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ) { |
|||
DPRINTF("%s unallowed IRQ group 0x%x\n", s->external ? "EXT" : "INT" |
|||
, group_n); |
|||
return; |
|||
} |
|||
|
|||
if (level) { |
|||
s->group[group_n].src_pending |= 1 << bit_n; |
|||
} else { |
|||
s->group[group_n].src_pending &= ~(1 << bit_n); |
|||
} |
|||
|
|||
exynos4210_combiner_update(s, group_n); |
|||
|
|||
return; |
|||
} |
|||
|
|||
static void exynos4210_combiner_reset(DeviceState *d) |
|||
{ |
|||
struct Exynos4210CombinerState *s = (struct Exynos4210CombinerState *)d; |
|||
|
|||
memset(&s->group, 0, sizeof(s->group)); |
|||
memset(&s->reg_set, 0, sizeof(s->reg_set)); |
|||
|
|||
s->reg_set[0xC0 >> 2] = 0x01010101; |
|||
s->reg_set[0xC4 >> 2] = 0x01010101; |
|||
s->reg_set[0xD0 >> 2] = 0x01010101; |
|||
s->reg_set[0xD4 >> 2] = 0x01010101; |
|||
} |
|||
|
|||
static const MemoryRegionOps exynos4210_combiner_ops = { |
|||
.read = exynos4210_combiner_read, |
|||
.write = exynos4210_combiner_write, |
|||
.endianness = DEVICE_NATIVE_ENDIAN, |
|||
}; |
|||
|
|||
/*
|
|||
* Internal Combiner initialization. |
|||
*/ |
|||
static int exynos4210_combiner_init(SysBusDevice *dev) |
|||
{ |
|||
unsigned int i; |
|||
struct Exynos4210CombinerState *s = |
|||
FROM_SYSBUS(struct Exynos4210CombinerState, dev); |
|||
|
|||
/* Allocate general purpose input signals and connect a handler to each of
|
|||
* them */ |
|||
qdev_init_gpio_in(&s->busdev.qdev, exynos4210_combiner_handler, IIC_NIRQ); |
|||
|
|||
/* Connect SysBusDev irqs to device specific irqs */ |
|||
for (i = 0; i < IIC_NIRQ; i++) { |
|||
sysbus_init_irq(dev, &s->output_irq[i]); |
|||
} |
|||
|
|||
memory_region_init_io(&s->iomem, &exynos4210_combiner_ops, s, |
|||
"exynos4210-combiner", IIC_REGION_SIZE); |
|||
sysbus_init_mmio(dev, &s->iomem); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static Property exynos4210_combiner_properties[] = { |
|||
DEFINE_PROP_UINT32("external", Exynos4210CombinerState, external, 0), |
|||
DEFINE_PROP_END_OF_LIST(), |
|||
}; |
|||
|
|||
static void exynos4210_combiner_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
|||
|
|||
k->init = exynos4210_combiner_init; |
|||
dc->reset = exynos4210_combiner_reset; |
|||
dc->props = exynos4210_combiner_properties; |
|||
dc->vmsd = &vmstate_exynos4210_combiner; |
|||
} |
|||
|
|||
static TypeInfo exynos4210_combiner_info = { |
|||
.name = "exynos4210.combiner", |
|||
.parent = TYPE_SYS_BUS_DEVICE, |
|||
.instance_size = sizeof(Exynos4210CombinerState), |
|||
.class_init = exynos4210_combiner_class_init, |
|||
}; |
|||
|
|||
static void exynos4210_combiner_register_types(void) |
|||
{ |
|||
type_register_static(&exynos4210_combiner_info); |
|||
} |
|||
|
|||
type_init(exynos4210_combiner_register_types) |
|||
@ -0,0 +1,458 @@ |
|||
/*
|
|||
* Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c |
|||
* |
|||
* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. |
|||
* All rights reserved. |
|||
* |
|||
* Evgeny Voevodin <e.voevodin@samsung.com> |
|||
* |
|||
* This program is free software; you can redistribute it and/or modify it |
|||
* under the terms of the GNU General Public License as published by the |
|||
* Free Software Foundation; either version 2 of the License, or (at your |
|||
* option) any later version. |
|||
* |
|||
* This program is distributed in the hope that it will be useful, |
|||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|||
* See the GNU General Public License for more details. |
|||
* |
|||
* You should have received a copy of the GNU General Public License along |
|||
* with this program; if not, see <http://www.gnu.org/licenses/>.
|
|||
*/ |
|||
|
|||
#include "sysbus.h" |
|||
#include "qemu-common.h" |
|||
#include "irq.h" |
|||
#include "exynos4210.h" |
|||
|
|||
enum ExtGicId { |
|||
EXT_GIC_ID_MDMA_LCD0 = 66, |
|||
EXT_GIC_ID_PDMA0, |
|||
EXT_GIC_ID_PDMA1, |
|||
EXT_GIC_ID_TIMER0, |
|||
EXT_GIC_ID_TIMER1, |
|||
EXT_GIC_ID_TIMER2, |
|||
EXT_GIC_ID_TIMER3, |
|||
EXT_GIC_ID_TIMER4, |
|||
EXT_GIC_ID_MCT_L0, |
|||
EXT_GIC_ID_WDT, |
|||
EXT_GIC_ID_RTC_ALARM, |
|||
EXT_GIC_ID_RTC_TIC, |
|||
EXT_GIC_ID_GPIO_XB, |
|||
EXT_GIC_ID_GPIO_XA, |
|||
EXT_GIC_ID_MCT_L1, |
|||
EXT_GIC_ID_IEM_APC, |
|||
EXT_GIC_ID_IEM_IEC, |
|||
EXT_GIC_ID_NFC, |
|||
EXT_GIC_ID_UART0, |
|||
EXT_GIC_ID_UART1, |
|||
EXT_GIC_ID_UART2, |
|||
EXT_GIC_ID_UART3, |
|||
EXT_GIC_ID_UART4, |
|||
EXT_GIC_ID_MCT_G0, |
|||
EXT_GIC_ID_I2C0, |
|||
EXT_GIC_ID_I2C1, |
|||
EXT_GIC_ID_I2C2, |
|||
EXT_GIC_ID_I2C3, |
|||
EXT_GIC_ID_I2C4, |
|||
EXT_GIC_ID_I2C5, |
|||
EXT_GIC_ID_I2C6, |
|||
EXT_GIC_ID_I2C7, |
|||
EXT_GIC_ID_SPI0, |
|||
EXT_GIC_ID_SPI1, |
|||
EXT_GIC_ID_SPI2, |
|||
EXT_GIC_ID_MCT_G1, |
|||
EXT_GIC_ID_USB_HOST, |
|||
EXT_GIC_ID_USB_DEVICE, |
|||
EXT_GIC_ID_MODEMIF, |
|||
EXT_GIC_ID_HSMMC0, |
|||
EXT_GIC_ID_HSMMC1, |
|||
EXT_GIC_ID_HSMMC2, |
|||
EXT_GIC_ID_HSMMC3, |
|||
EXT_GIC_ID_SDMMC, |
|||
EXT_GIC_ID_MIPI_CSI_4LANE, |
|||
EXT_GIC_ID_MIPI_DSI_4LANE, |
|||
EXT_GIC_ID_MIPI_CSI_2LANE, |
|||
EXT_GIC_ID_MIPI_DSI_2LANE, |
|||
EXT_GIC_ID_ONENAND_AUDI, |
|||
EXT_GIC_ID_ROTATOR, |
|||
EXT_GIC_ID_FIMC0, |
|||
EXT_GIC_ID_FIMC1, |
|||
EXT_GIC_ID_FIMC2, |
|||
EXT_GIC_ID_FIMC3, |
|||
EXT_GIC_ID_JPEG, |
|||
EXT_GIC_ID_2D, |
|||
EXT_GIC_ID_PCIe, |
|||
EXT_GIC_ID_MIXER, |
|||
EXT_GIC_ID_HDMI, |
|||
EXT_GIC_ID_HDMI_I2C, |
|||
EXT_GIC_ID_MFC, |
|||
EXT_GIC_ID_TVENC, |
|||
}; |
|||
|
|||
enum ExtInt { |
|||
EXT_GIC_ID_EXTINT0 = 48, |
|||
EXT_GIC_ID_EXTINT1, |
|||
EXT_GIC_ID_EXTINT2, |
|||
EXT_GIC_ID_EXTINT3, |
|||
EXT_GIC_ID_EXTINT4, |
|||
EXT_GIC_ID_EXTINT5, |
|||
EXT_GIC_ID_EXTINT6, |
|||
EXT_GIC_ID_EXTINT7, |
|||
EXT_GIC_ID_EXTINT8, |
|||
EXT_GIC_ID_EXTINT9, |
|||
EXT_GIC_ID_EXTINT10, |
|||
EXT_GIC_ID_EXTINT11, |
|||
EXT_GIC_ID_EXTINT12, |
|||
EXT_GIC_ID_EXTINT13, |
|||
EXT_GIC_ID_EXTINT14, |
|||
EXT_GIC_ID_EXTINT15 |
|||
}; |
|||
|
|||
/*
|
|||
* External GIC sources which are not from External Interrupt Combiner or |
|||
* External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ, |
|||
* which is INTG16 in Internal Interrupt Combiner. |
|||
*/ |
|||
|
|||
static uint32_t |
|||
combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = { |
|||
/* int combiner groups 16-19 */ |
|||
{ }, { }, { }, { }, |
|||
/* int combiner group 20 */ |
|||
{ 0, EXT_GIC_ID_MDMA_LCD0 }, |
|||
/* int combiner group 21 */ |
|||
{ EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 }, |
|||
/* int combiner group 22 */ |
|||
{ EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2, |
|||
EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 }, |
|||
/* int combiner group 23 */ |
|||
{ EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC }, |
|||
/* int combiner group 24 */ |
|||
{ EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA }, |
|||
/* int combiner group 25 */ |
|||
{ EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC }, |
|||
/* int combiner group 26 */ |
|||
{ EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3, |
|||
EXT_GIC_ID_UART4 }, |
|||
/* int combiner group 27 */ |
|||
{ EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3, |
|||
EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6, |
|||
EXT_GIC_ID_I2C7 }, |
|||
/* int combiner group 28 */ |
|||
{ EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 }, |
|||
/* int combiner group 29 */ |
|||
{ EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2, |
|||
EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC }, |
|||
/* int combiner group 30 */ |
|||
{ EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE }, |
|||
/* int combiner group 31 */ |
|||
{ EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE }, |
|||
/* int combiner group 32 */ |
|||
{ EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 }, |
|||
/* int combiner group 33 */ |
|||
{ EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 }, |
|||
/* int combiner group 34 */ |
|||
{ EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC }, |
|||
/* int combiner group 35 */ |
|||
{ 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, |
|||
/* int combiner group 36 */ |
|||
{ EXT_GIC_ID_MIXER }, |
|||
/* int combiner group 37 */ |
|||
{ EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6, |
|||
EXT_GIC_ID_EXTINT7 }, |
|||
/* groups 38-50 */ |
|||
{ }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, |
|||
/* int combiner group 51 */ |
|||
{ EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, |
|||
/* group 52 */ |
|||
{ }, |
|||
/* int combiner group 53 */ |
|||
{ EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 }, |
|||
/* groups 54-63 */ |
|||
{ }, { }, { }, { }, { }, { }, { }, { }, { }, { } |
|||
}; |
|||
|
|||
#define EXYNOS4210_GIC_NIRQ 160 |
|||
#define NCPU EXYNOS4210_NCPUS |
|||
|
|||
#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000 |
|||
#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000 |
|||
|
|||
#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000 |
|||
#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \ |
|||
((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET) |
|||
#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \ |
|||
((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET) |
|||
|
|||
#define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100 |
|||
#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000 |
|||
|
|||
static void exynos4210_irq_handler(void *opaque, int irq, int level) |
|||
{ |
|||
Exynos4210Irq *s = (Exynos4210Irq *)opaque; |
|||
|
|||
/* Bypass */ |
|||
qemu_set_irq(s->board_irqs[irq], level); |
|||
|
|||
return; |
|||
} |
|||
|
|||
/*
|
|||
* Initialize exynos4210 IRQ subsystem stub. |
|||
*/ |
|||
qemu_irq *exynos4210_init_irq(Exynos4210Irq *s) |
|||
{ |
|||
return qemu_allocate_irqs(exynos4210_irq_handler, s, |
|||
EXYNOS4210_MAX_INT_COMBINER_IN_IRQ); |
|||
} |
|||
|
|||
/*
|
|||
* Initialize board IRQs. |
|||
* These IRQs contain splitted Int/External Combiner and External Gic IRQs. |
|||
*/ |
|||
void exynos4210_init_board_irqs(Exynos4210Irq *s) |
|||
{ |
|||
uint32_t grp, bit, irq_id, n; |
|||
|
|||
for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) { |
|||
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], |
|||
s->ext_combiner_irq[n]); |
|||
|
|||
irq_id = 0; |
|||
if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) || |
|||
n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) { |
|||
/* MCT_G0 is passed to External GIC */ |
|||
irq_id = EXT_GIC_ID_MCT_G0; |
|||
} |
|||
if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) || |
|||
n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) { |
|||
/* MCT_G1 is passed to External and GIC */ |
|||
irq_id = EXT_GIC_ID_MCT_G1; |
|||
} |
|||
if (irq_id) { |
|||
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], |
|||
s->ext_gic_irq[irq_id-32]); |
|||
} |
|||
|
|||
} |
|||
for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) { |
|||
/* these IDs are passed to Internal Combiner and External GIC */ |
|||
grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n); |
|||
bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n); |
|||
irq_id = combiner_grp_to_gic_id[grp - |
|||
EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit]; |
|||
|
|||
if (irq_id) { |
|||
s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n], |
|||
s->ext_gic_irq[irq_id-32]); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Get IRQ number from exynos4210 IRQ subsystem stub. |
|||
* To identify IRQ source use internal combiner group and bit number |
|||
* grp - group number |
|||
* bit - bit number inside group |
|||
*/ |
|||
uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit) |
|||
{ |
|||
return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit); |
|||
} |
|||
|
|||
/********* GIC part *********/ |
|||
|
|||
static inline int |
|||
gic_get_current_cpu(void) |
|||
{ |
|||
return cpu_single_env->cpu_index; |
|||
} |
|||
|
|||
#include "arm_gic.c" |
|||
|
|||
typedef struct { |
|||
gic_state gic; |
|||
MemoryRegion cpu_container; |
|||
MemoryRegion dist_container; |
|||
MemoryRegion cpu_alias[NCPU]; |
|||
MemoryRegion dist_alias[NCPU]; |
|||
uint32_t num_cpu; |
|||
} Exynos4210GicState; |
|||
|
|||
static int exynos4210_gic_init(SysBusDevice *dev) |
|||
{ |
|||
Exynos4210GicState *s = FROM_SYSBUSGIC(Exynos4210GicState, dev); |
|||
uint32_t i; |
|||
const char cpu_prefix[] = "exynos4210-gic-alias_cpu"; |
|||
const char dist_prefix[] = "exynos4210-gic-alias_dist"; |
|||
char cpu_alias_name[sizeof(cpu_prefix) + 3]; |
|||
char dist_alias_name[sizeof(cpu_prefix) + 3]; |
|||
|
|||
gic_init(&s->gic, s->num_cpu, EXYNOS4210_GIC_NIRQ); |
|||
|
|||
memory_region_init(&s->cpu_container, "exynos4210-cpu-container", |
|||
EXYNOS4210_EXT_GIC_CPU_REGION_SIZE); |
|||
memory_region_init(&s->dist_container, "exynos4210-dist-container", |
|||
EXYNOS4210_EXT_GIC_DIST_REGION_SIZE); |
|||
|
|||
for (i = 0; i < s->num_cpu; i++) { |
|||
/* Map CPU interface per SMP Core */ |
|||
sprintf(cpu_alias_name, "%s%x", cpu_prefix, i); |
|||
memory_region_init_alias(&s->cpu_alias[i], |
|||
cpu_alias_name, |
|||
&s->gic.cpuiomem[0], |
|||
0, |
|||
EXYNOS4210_GIC_CPU_REGION_SIZE); |
|||
memory_region_add_subregion(&s->cpu_container, |
|||
EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]); |
|||
|
|||
/* Map Distributor per SMP Core */ |
|||
sprintf(dist_alias_name, "%s%x", dist_prefix, i); |
|||
memory_region_init_alias(&s->dist_alias[i], |
|||
dist_alias_name, |
|||
&s->gic.iomem, |
|||
0, |
|||
EXYNOS4210_GIC_DIST_REGION_SIZE); |
|||
memory_region_add_subregion(&s->dist_container, |
|||
EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]); |
|||
} |
|||
|
|||
sysbus_init_mmio(dev, &s->cpu_container); |
|||
sysbus_init_mmio(dev, &s->dist_container); |
|||
|
|||
gic_cpu_write(&s->gic, 1, 0, 1); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static Property exynos4210_gic_properties[] = { |
|||
DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1), |
|||
DEFINE_PROP_END_OF_LIST(), |
|||
}; |
|||
|
|||
static void exynos4210_gic_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
|||
|
|||
k->init = exynos4210_gic_init; |
|||
dc->props = exynos4210_gic_properties; |
|||
} |
|||
|
|||
static TypeInfo exynos4210_gic_info = { |
|||
.name = "exynos4210.gic", |
|||
.parent = TYPE_SYS_BUS_DEVICE, |
|||
.instance_size = sizeof(Exynos4210GicState), |
|||
.class_init = exynos4210_gic_class_init, |
|||
}; |
|||
|
|||
static void exynos4210_gic_register_types(void) |
|||
{ |
|||
type_register_static(&exynos4210_gic_info); |
|||
} |
|||
|
|||
type_init(exynos4210_gic_register_types) |
|||
|
|||
/*
|
|||
* IRQGate struct. |
|||
* IRQ Gate represents OR gate between GICs to pass IRQ to PIC. |
|||
*/ |
|||
typedef struct { |
|||
SysBusDevice busdev; |
|||
|
|||
qemu_irq pic_irq[NCPU]; /* output IRQs to PICs */ |
|||
uint32_t gpio_level[EXYNOS4210_IRQ_GATE_NINPUTS]; /* Input levels */ |
|||
} Exynos4210IRQGateState; |
|||
|
|||
static const VMStateDescription vmstate_exynos4210_irq_gate = { |
|||
.name = "exynos4210.irq_gate", |
|||
.version_id = 1, |
|||
.minimum_version_id = 1, |
|||
.minimum_version_id_old = 1, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_UINT32_ARRAY(gpio_level, Exynos4210IRQGateState, |
|||
EXYNOS4210_IRQ_GATE_NINPUTS), |
|||
VMSTATE_END_OF_LIST() |
|||
} |
|||
}; |
|||
|
|||
/* Process a change in an external IRQ input. */ |
|||
static void exynos4210_irq_gate_handler(void *opaque, int irq, int level) |
|||
{ |
|||
Exynos4210IRQGateState *s = |
|||
(Exynos4210IRQGateState *)opaque; |
|||
uint32_t odd, even; |
|||
|
|||
if (irq & 1) { |
|||
odd = irq; |
|||
even = irq & ~1; |
|||
} else { |
|||
even = irq; |
|||
odd = irq | 1; |
|||
} |
|||
|
|||
assert(irq < EXYNOS4210_IRQ_GATE_NINPUTS); |
|||
s->gpio_level[irq] = level; |
|||
|
|||
if (s->gpio_level[odd] >= 1 || s->gpio_level[even] >= 1) { |
|||
qemu_irq_raise(s->pic_irq[even >> 1]); |
|||
} else { |
|||
qemu_irq_lower(s->pic_irq[even >> 1]); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
static void exynos4210_irq_gate_reset(DeviceState *d) |
|||
{ |
|||
Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)d; |
|||
|
|||
memset(&s->gpio_level, 0, sizeof(s->gpio_level)); |
|||
} |
|||
|
|||
/*
|
|||
* IRQ Gate initialization. |
|||
*/ |
|||
static int exynos4210_irq_gate_init(SysBusDevice *dev) |
|||
{ |
|||
unsigned int i; |
|||
Exynos4210IRQGateState *s = |
|||
FROM_SYSBUS(Exynos4210IRQGateState, dev); |
|||
|
|||
/* Allocate general purpose input signals and connect a handler to each of
|
|||
* them */ |
|||
qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, |
|||
EXYNOS4210_IRQ_GATE_NINPUTS); |
|||
|
|||
/* Connect SysBusDev irqs to device specific irqs */ |
|||
for (i = 0; i < NCPU; i++) { |
|||
sysbus_init_irq(dev, &s->pic_irq[i]); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); |
|||
|
|||
k->init = exynos4210_irq_gate_init; |
|||
dc->reset = exynos4210_irq_gate_reset; |
|||
dc->vmsd = &vmstate_exynos4210_irq_gate; |
|||
} |
|||
|
|||
static TypeInfo exynos4210_irq_gate_info = { |
|||
.name = "exynos4210.irq_gate", |
|||
.parent = TYPE_SYS_BUS_DEVICE, |
|||
.instance_size = sizeof(Exynos4210IRQGateState), |
|||
.class_init = exynos4210_irq_gate_class_init, |
|||
}; |
|||
|
|||
static void exynos4210_irq_gate_register_types(void) |
|||
{ |
|||
type_register_static(&exynos4210_irq_gate_info); |
|||
} |
|||
|
|||
type_init(exynos4210_irq_gate_register_types) |
|||
Loading…
Reference in new issue