577 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			577 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | /*
 | ||
|  |  * Copyright (c) 2006-2022, RT-Thread Development Team | ||
|  |  * | ||
|  |  * SPDX-License-Identifier: Apache-2.0 | ||
|  |  * | ||
|  |  * Change Logs: | ||
|  |  * Date           Author       Notes | ||
|  |  * 2013-07-20     Bernard      first version | ||
|  |  * 2014-04-03     Grissiom     many enhancements | ||
|  |  * 2018-11-22     Jesven       add rt_hw_ipi_send() | ||
|  |  *                             add rt_hw_ipi_handler_install() | ||
|  |  * 2022-08-24     GuEe-GUI     add pic support | ||
|  |  * 2022-11-07     GuEe-GUI     add v2m support | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <rthw.h>
 | ||
|  | #include <rtthread.h>
 | ||
|  | #include <rtdevice.h>
 | ||
|  | 
 | ||
|  | #define DBG_TAG "pic.gicv2"
 | ||
|  | #define DBG_LVL DBG_INFO
 | ||
|  | #include <rtdbg.h>
 | ||
|  | 
 | ||
|  | #include <cpuport.h>
 | ||
|  | 
 | ||
|  | #include <ioremap.h>
 | ||
|  | 
 | ||
|  | #include "pic-gicv2.h"
 | ||
|  | #include "pic-gic-common.h"
 | ||
|  | 
 | ||
|  | #define GIC_CPU_IMAX 8
 | ||
|  | 
 | ||
|  | #define raw_to_gicv2(raw) rt_container_of(raw, struct gicv2, parent)
 | ||
|  | 
 | ||
|  | static rt_bool_t needs_rmw_access = RT_FALSE; | ||
|  | static int _gicv2_nr = 0, _init_cpu_id = 0; | ||
|  | static struct gicv2 _gicv2_list[RT_PIC_ARM_GIC_MAX_NR] = {}; | ||
|  | static rt_bool_t _gicv2_eoi_mode_ns = RT_FALSE; | ||
|  | static rt_uint8_t _gicv2_cpumask_map[GIC_CPU_IMAX] = | ||
|  | { | ||
|  |     [0 ... GIC_CPU_IMAX - 1] = 0xff, | ||
|  | }; | ||
|  | 
 | ||
|  | static rt_uint8_t gicv2_cpumask_map(struct gicv2 *gic) | ||
|  | { | ||
|  |     rt_uint32_t mask, i; | ||
|  | 
 | ||
|  |     for (i = mask = 0; i < 32; i += 4) | ||
|  |     { | ||
|  |         mask = HWREG32(gic->dist_base + GIC_DIST_TARGET + i); | ||
|  |         mask |= mask >> 16; | ||
|  |         mask |= mask >> 8; | ||
|  | 
 | ||
|  |         if (mask) | ||
|  |         { | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return mask; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_dist_init(struct gicv2 *gic) | ||
|  | { | ||
|  |     void *base = gic->dist_base; | ||
|  |     rt_uint32_t i; | ||
|  |     rt_uint32_t cpumask = gicv2_cpumask_map(gic); | ||
|  | 
 | ||
|  |     gic->max_irq = HWREG32(base + GIC_DIST_TYPE) & 0x1f; | ||
|  |     gic->max_irq = (gic->max_irq + 1) * 32; | ||
|  | 
 | ||
|  |     /*
 | ||
|  |      * The GIC only supports up to 1020 interrupt sources. | ||
|  |      * Limit this to either the architected maximum, or the | ||
|  |      * platform maximum. | ||
|  |      */ | ||
|  |     if (gic->max_irq > 1020) | ||
|  |     { | ||
|  |         gic->max_irq = 1020; | ||
|  |     } | ||
|  | 
 | ||
|  |     LOG_D("Max irq = %d", gic->max_irq); | ||
|  | 
 | ||
|  |     HWREG32(base + GIC_DIST_CTRL) = GICD_DISABLE; | ||
|  | 
 | ||
|  |     /* Set all global (unused) interrupts to this CPU only. */ | ||
|  |     cpumask |= cpumask << 8; | ||
|  |     cpumask |= cpumask << 16; | ||
|  | 
 | ||
|  |     for (i = 32; i < gic->max_irq; i += 4) | ||
|  |     { | ||
|  |         HWREG32(base + GIC_DIST_TARGET + i * 4 / 4) = cpumask; | ||
|  |     } | ||
|  | 
 | ||
|  |     gic_common_dist_config(base, gic->max_irq, RT_NULL, RT_NULL); | ||
|  | 
 | ||
|  |     HWREG32(base + GIC_DIST_CTRL) = GICD_ENABLE; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_cpu_init(struct gicv2 *gic) | ||
|  | { | ||
|  |     rt_uint32_t cpumask; | ||
|  |     void *base = gic->cpu_base; | ||
|  |     rt_uint32_t config = GICC_ENABLE; | ||
|  |     int cpu_id = _init_cpu_id = rt_hw_cpu_id(); | ||
|  | 
 | ||
|  |     cpumask = gicv2_cpumask_map(gic); | ||
|  |     _gicv2_cpumask_map[cpu_id] = cpumask; | ||
|  | 
 | ||
|  |     /*
 | ||
|  |      * Clear our mask from the other map entries in case they're | ||
|  |      * still undefined. | ||
|  |      */ | ||
|  |     for (int i = 0; i < RT_ARRAY_SIZE(_gicv2_cpumask_map); ++i) | ||
|  |     { | ||
|  |         if (i != cpu_id) | ||
|  |         { | ||
|  |             _gicv2_cpumask_map[i] &= ~cpumask; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     gic_common_cpu_config(gic->dist_base, 32, RT_NULL, RT_NULL); | ||
|  | 
 | ||
|  |     HWREG32(base + GIC_CPU_PRIMASK) = GICC_INT_PRI_THRESHOLD; | ||
|  |     HWREG32(base + GIC_CPU_BINPOINT) = 0x7; | ||
|  | 
 | ||
|  | #ifdef ARCH_SUPPORT_HYP
 | ||
|  |     _gicv2_eoi_mode_ns = RT_TRUE; | ||
|  | #endif
 | ||
|  | 
 | ||
|  |     if (_gicv2_eoi_mode_ns) | ||
|  |     { | ||
|  |         config |= GIC_CPU_CTRL_EOI_MODE_NS; | ||
|  |     } | ||
|  | 
 | ||
|  |     HWREG32(base + GIC_CPU_CTRL) = config; | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_irq_init(struct rt_pic *pic) | ||
|  | { | ||
|  |     gicv2_cpu_init(rt_container_of(pic, struct gicv2, parent)); | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_irq_ack(struct rt_pic_irq *pirq) | ||
|  | { | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     if (!_gicv2_eoi_mode_ns) | ||
|  |     { | ||
|  |         HWREG32(gic->dist_base + GIC_DIST_PENDING_CLEAR + hwirq / 32 * 4) = 1U << (hwirq % 32); | ||
|  |     } | ||
|  | 
 | ||
|  |     HWREG32(gic->cpu_base + GIC_CPU_EOI) = hwirq; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_irq_mask(struct rt_pic_irq *pirq) | ||
|  | { | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     HWREG32(gic->dist_base + GIC_DIST_ENABLE_CLEAR + hwirq / 32 * 4) = 1U << (hwirq % 32); | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_irq_unmask(struct rt_pic_irq *pirq) | ||
|  | { | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     HWREG32(gic->dist_base + GIC_DIST_ENABLE_SET + hwirq / 32 * 4) = 1U << (hwirq % 32); | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_irq_eoi(struct rt_pic_irq *pirq) | ||
|  | { | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     if (_gicv2_eoi_mode_ns) | ||
|  |     { | ||
|  |         HWREG32(gic->cpu_base + GIC_CPU_DIR) = pirq->hwirq; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_irq_set_priority(struct rt_pic_irq *pirq, rt_uint32_t priority) | ||
|  | { | ||
|  |     rt_uint32_t mask; | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     mask = HWREG32(gic->dist_base + GIC_DIST_PRI + hwirq / 4 * 4); | ||
|  |     mask &= ~(0xffU << ((hwirq % 4) * 8)); | ||
|  |     mask |= ((priority & 0xffU) << ((hwirq % 4) * 8)); | ||
|  |     HWREG32(gic->dist_base + GIC_DIST_PRI + hwirq / 4 * 4) = mask; | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_irq_set_affinity(struct rt_pic_irq *pirq, rt_bitmap_t *affinity) | ||
|  | { | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  |     rt_uint32_t target_list = ((rt_uint8_t *)affinity)[gic - &_gicv2_list[0]]; | ||
|  |     rt_uint8_t valb = _gicv2_cpumask_map[__rt_ffs(target_list) - 1]; | ||
|  |     void *io_addr = gic->dist_base + GIC_DIST_TARGET + hwirq; | ||
|  | 
 | ||
|  |     if (needs_rmw_access) | ||
|  |     { | ||
|  |         /* RMW write byte */ | ||
|  |         rt_uint32_t val; | ||
|  |         rt_ubase_t level; | ||
|  |         rt_ubase_t offset = (rt_ubase_t)io_addr & 3UL, shift = offset * 8; | ||
|  |         static struct rt_spinlock rmw_lock = {}; | ||
|  | 
 | ||
|  |         level = rt_spin_lock_irqsave(&rmw_lock); | ||
|  | 
 | ||
|  |         io_addr -= offset; | ||
|  |         val = HWREG32(io_addr); | ||
|  |         val &= ~RT_GENMASK(shift + 7, shift); | ||
|  |         val |= valb << shift; | ||
|  |         HWREG32(io_addr) = val; | ||
|  | 
 | ||
|  |         rt_spin_unlock_irqrestore(&rmw_lock, level); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         HWREG8(io_addr) = valb; | ||
|  |     } | ||
|  | 
 | ||
|  |     return RT_EOK; | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_irq_set_triger_mode(struct rt_pic_irq *pirq, rt_uint32_t mode) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  |     int hwirq = pirq->hwirq; | ||
|  |     struct gicv2 *gic = raw_to_gicv2(pirq->pic); | ||
|  | 
 | ||
|  |     if (hwirq >= GIC_SGI_NR) | ||
|  |     { | ||
|  |         err = gic_common_configure_irq(gic->dist_base + GIC_DIST_CONFIG, pirq->hwirq, mode, RT_NULL, RT_NULL); | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         err = -RT_ENOSYS; | ||
|  |     } | ||
|  | 
 | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_irq_send_ipi(struct rt_pic_irq *pirq, rt_bitmap_t *cpumask) | ||
|  | { | ||
|  |     struct gicv2 *gic; | ||
|  |     int sgi = pirq->hwirq; | ||
|  |     rt_uint8_t *target_list = (rt_uint8_t *)cpumask; | ||
|  | 
 | ||
|  |     for (int i = 0; i < _gicv2_nr; ++i) | ||
|  |     { | ||
|  |         if (*target_list) | ||
|  |         { | ||
|  |             gic = &_gicv2_list[i]; | ||
|  | 
 | ||
|  |             HWREG32(gic->dist_base + GIC_DIST_SOFTINT) = ((*target_list & 0xffU) << 16) | (sgi & 0xf); | ||
|  | 
 | ||
|  |             rt_hw_dsb(); | ||
|  |         } | ||
|  | 
 | ||
|  |         ++target_list; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | static int gicv2_irq_map(struct rt_pic *pic, int hwirq, rt_uint32_t mode) | ||
|  | { | ||
|  |     int irq, irq_index = hwirq - GIC_SGI_NR; | ||
|  |     struct rt_pic_irq *pirq = rt_pic_find_irq(pic, irq_index); | ||
|  | 
 | ||
|  |     if (pirq && hwirq >= GIC_SGI_NR) | ||
|  |     { | ||
|  |         pirq->mode = mode; | ||
|  |         pirq->priority = GICD_INT_DEF_PRI; | ||
|  |         rt_bitmap_set_bit(pirq->affinity, _init_cpu_id); | ||
|  | 
 | ||
|  |         irq = rt_pic_config_irq(pic, irq_index, hwirq); | ||
|  | 
 | ||
|  |         if (irq >= 0 && mode != RT_IRQ_MODE_LEVEL_HIGH) | ||
|  |         { | ||
|  |             gicv2_irq_set_triger_mode(pirq, mode); | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         irq = -1; | ||
|  |     } | ||
|  | 
 | ||
|  |     return irq; | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_irq_parse(struct rt_pic *pic, struct rt_ofw_cell_args *args, struct rt_pic_irq *out_pirq) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  | 
 | ||
|  |     if (args->args_count == 3) | ||
|  |     { | ||
|  |         out_pirq->mode = args->args[2] & RT_IRQ_MODE_MASK; | ||
|  | 
 | ||
|  |         switch (args->args[0]) | ||
|  |         { | ||
|  |         case 0: | ||
|  |             /* SPI */ | ||
|  |             out_pirq->hwirq = args->args[1] + 32; | ||
|  |             break; | ||
|  |         case 1: | ||
|  |             /* PPI */ | ||
|  |             out_pirq->hwirq = args->args[1] + 16; | ||
|  |             break; | ||
|  |         default: | ||
|  |             err = -RT_ENOSYS; | ||
|  |             break; | ||
|  |         } | ||
|  |     } | ||
|  |     else | ||
|  |     { | ||
|  |         err = -RT_EINVAL; | ||
|  |     } | ||
|  | 
 | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | static struct rt_pic_ops gicv2_ops = | ||
|  | { | ||
|  |     .name = "GICv2", | ||
|  |     .irq_init = gicv2_irq_init, | ||
|  |     .irq_ack = gicv2_irq_ack, | ||
|  |     .irq_mask = gicv2_irq_mask, | ||
|  |     .irq_unmask = gicv2_irq_unmask, | ||
|  |     .irq_eoi = gicv2_irq_eoi, | ||
|  |     .irq_set_priority = gicv2_irq_set_priority, | ||
|  |     .irq_set_affinity = gicv2_irq_set_affinity, | ||
|  |     .irq_set_triger_mode = gicv2_irq_set_triger_mode, | ||
|  |     .irq_send_ipi = gicv2_irq_send_ipi, | ||
|  |     .irq_map = gicv2_irq_map, | ||
|  |     .irq_parse = gicv2_irq_parse, | ||
|  | }; | ||
|  | 
 | ||
|  | static rt_bool_t gicv2_handler(void *data) | ||
|  | { | ||
|  |     rt_bool_t res = RT_FALSE; | ||
|  |     int hwirq; | ||
|  |     struct gicv2 *gic = data; | ||
|  | 
 | ||
|  |     hwirq = HWREG32(gic->cpu_base + GIC_CPU_INTACK) & 0x3ffUL; | ||
|  | 
 | ||
|  |     if (!(hwirq >= 1020 && hwirq <= 1023)) | ||
|  |     { | ||
|  |         struct rt_pic_irq *pirq; | ||
|  | 
 | ||
|  |         if (hwirq < GIC_SGI_NR) | ||
|  |         { | ||
|  |             rt_hw_rmb(); | ||
|  | 
 | ||
|  |             pirq = rt_pic_find_ipi(&gic->parent, hwirq); | ||
|  |         } | ||
|  |         else | ||
|  |         { | ||
|  |             pirq = rt_pic_find_irq(&gic->parent, hwirq - GIC_SGI_NR); | ||
|  |         } | ||
|  | 
 | ||
|  |         gicv2_irq_ack(pirq); | ||
|  | 
 | ||
|  |         rt_pic_handle_isr(pirq); | ||
|  | 
 | ||
|  |         gicv2_irq_eoi(pirq); | ||
|  | 
 | ||
|  |         res = RT_TRUE; | ||
|  |     } | ||
|  | 
 | ||
|  |     return res; | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_enable_rmw_access(void *data) | ||
|  | { | ||
|  |     if (rt_ofw_machine_is_compatible("renesas,emev2")) | ||
|  |     { | ||
|  |         needs_rmw_access = RT_TRUE; | ||
|  |         return RT_EOK; | ||
|  |     } | ||
|  | 
 | ||
|  |     return -RT_EINVAL; | ||
|  | } | ||
|  | 
 | ||
|  | static const struct gic_quirk _gicv2_quirks[] = | ||
|  | { | ||
|  |     { | ||
|  |         .desc       = "GICv2: Broken byte access", | ||
|  |         .compatible = "arm,pl390", | ||
|  |         .init       = gicv2_enable_rmw_access, | ||
|  |     }, | ||
|  |     { /* sentinel */ } | ||
|  | }; | ||
|  | 
 | ||
|  | static rt_err_t gicv2_iomap_init(struct gicv2 *gic, rt_uint64_t *regs) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  |     int idx; | ||
|  |     const char *name[] = | ||
|  |     { | ||
|  |         "Distributor", | ||
|  |         "CPU interfaces", | ||
|  |         "Virtual interface control", | ||
|  |         "Virtual CPU interface", | ||
|  |     }; | ||
|  | 
 | ||
|  |     do { | ||
|  |         /* GICD->GICC->GICH->GICV */ | ||
|  |         gic->dist_size = regs[1]; | ||
|  |         gic->dist_base = rt_ioremap((void *)regs[0], gic->dist_size); | ||
|  |         if (!gic->dist_base) | ||
|  |         { | ||
|  |             idx = 0; | ||
|  |             err = -RT_ERROR; | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         gic->cpu_size = regs[3]; | ||
|  |         gic->cpu_base = rt_ioremap((void *)regs[2], gic->cpu_size); | ||
|  |         if (!gic->cpu_base) | ||
|  |         { | ||
|  |             idx = 1; | ||
|  |             err = -RT_ERROR; | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         /* ArchRev[4:7] */ | ||
|  |         gic->version = HWREG32(gic->dist_base + GIC_DIST_ICPIDR2) >> 4; | ||
|  | 
 | ||
|  |     #ifdef ARCH_SUPPORT_HYP
 | ||
|  |         if (gic->version == 1) | ||
|  |         { | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         gic->hyp_size = regs[5]; | ||
|  |         gic->hyp_base = rt_ioremap((void *)regs[4], gic->hyp_size); | ||
|  |         if (!gic->hyp_base) | ||
|  |         { | ||
|  |             idx = 2; | ||
|  |             err = -RT_ERROR; | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         gic->vcpu_size = regs[7]; | ||
|  |         gic->vcpu_base = rt_ioremap((void *)regs[6], gic->vcpu_size); | ||
|  |         if (!gic->vcpu_base) | ||
|  |         { | ||
|  |             idx = 3; | ||
|  |             err = -RT_ERROR; | ||
|  |             break; | ||
|  |         } | ||
|  |     #endif /* ARCH_SUPPORT_HYP */
 | ||
|  |     } while (0); | ||
|  | 
 | ||
|  |     if (err) | ||
|  |     { | ||
|  |         RT_UNUSED(idx); | ||
|  |         RT_UNUSED(name); | ||
|  | 
 | ||
|  |         LOG_E("gic[%d] %s IO[%p, %p] map fail", _gicv2_nr, name[idx], regs[idx * 2], regs[idx * 2 + 1]); | ||
|  |     } | ||
|  | 
 | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_init(struct gicv2 *gic) | ||
|  | { | ||
|  |     gicv2_dist_init(gic); | ||
|  | 
 | ||
|  |     gic->parent.priv_data = gic; | ||
|  |     gic->parent.ops = &gicv2_ops; | ||
|  | 
 | ||
|  |     rt_pic_linear_irq(&gic->parent, gic->max_irq + 1 - GIC_SGI_NR); | ||
|  |     gic_common_sgi_config(gic->dist_base, &gic->parent, _gicv2_nr * GIC_SGI_NR); | ||
|  | 
 | ||
|  |     rt_pic_add_traps(gicv2_handler, gic); | ||
|  | 
 | ||
|  |     rt_pic_user_extends(&gic->parent); | ||
|  | } | ||
|  | 
 | ||
|  | static void gicv2_init_fail(struct gicv2 *gic) | ||
|  | { | ||
|  |     if (gic->dist_base) | ||
|  |     { | ||
|  |         rt_iounmap(gic->dist_base); | ||
|  |     } | ||
|  |     if (gic->cpu_base) | ||
|  |     { | ||
|  |         rt_iounmap(gic->cpu_base); | ||
|  |     } | ||
|  |     if (gic->hyp_base) | ||
|  |     { | ||
|  |         rt_iounmap(gic->hyp_base); | ||
|  |     } | ||
|  |     if (gic->vcpu_base) | ||
|  |     { | ||
|  |         rt_iounmap(gic->vcpu_base); | ||
|  |     } | ||
|  |     rt_memset(gic, 0, sizeof(*gic)); | ||
|  | } | ||
|  | 
 | ||
|  | static rt_err_t gicv2_ofw_init(struct rt_ofw_node *np, const struct rt_ofw_node_id *id) | ||
|  | { | ||
|  |     rt_err_t err = RT_EOK; | ||
|  |     struct gicv2 *gic = RT_NULL; | ||
|  | 
 | ||
|  |     do { | ||
|  |         rt_uint64_t regs[8]; | ||
|  | 
 | ||
|  |         if (_gicv2_nr >= RT_PIC_ARM_GIC_MAX_NR) | ||
|  |         { | ||
|  |             LOG_W("GICv2/v1 table is full"); | ||
|  |             err = -RT_EFULL; | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         gic = &_gicv2_list[_gicv2_nr]; | ||
|  | 
 | ||
|  |         rt_ofw_get_address_array(np, RT_ARRAY_SIZE(regs), regs); | ||
|  | 
 | ||
|  |         if ((err = gicv2_iomap_init(gic, regs))) | ||
|  |         { | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         if (gic->version != 1 && gic->version != 2) | ||
|  |         { | ||
|  |             LOG_E("Version = %d is not support", gic->version); | ||
|  |             err = -RT_EINVAL; | ||
|  |             break; | ||
|  |         } | ||
|  | 
 | ||
|  |         gic_common_init_quirk_ofw(np, _gicv2_quirks, gic); | ||
|  |         gicv2_init(gic); | ||
|  | 
 | ||
|  |         rt_ofw_data(np) = &gic->parent; | ||
|  | 
 | ||
|  |         if (gic->version == 2) | ||
|  |         { | ||
|  |         #ifdef RT_PIC_ARM_GIC_V2M
 | ||
|  |             gicv2m_ofw_probe(np, id); | ||
|  |         #endif
 | ||
|  |         } | ||
|  | 
 | ||
|  |         ++_gicv2_nr; | ||
|  |     } while (0); | ||
|  | 
 | ||
|  |     if (err && gic) | ||
|  |     { | ||
|  |         gicv2_init_fail(gic); | ||
|  |     } | ||
|  | 
 | ||
|  |     return err; | ||
|  | } | ||
|  | 
 | ||
|  | static const struct rt_ofw_node_id gicv2_ofw_ids[] = | ||
|  | { | ||
|  |     { .compatible = "arm,gic-400" }, | ||
|  |     { .compatible = "arm,arm11mp-gic" }, | ||
|  |     { .compatible = "arm,arm1176jzf-devchip-gic" }, | ||
|  |     { .compatible = "arm,cortex-a15-gic" }, | ||
|  |     { .compatible = "arm,cortex-a9-gic" }, | ||
|  |     { .compatible = "arm,cortex-a7-gic" }, | ||
|  |     { .compatible = "qcom,msm-8660-qgic" }, | ||
|  |     { .compatible = "qcom,msm-qgic2" }, | ||
|  |     { .compatible = "arm,pl390" }, | ||
|  |     { /* sentinel */ } | ||
|  | }; | ||
|  | RT_PIC_OFW_DECLARE(gicv2, gicv2_ofw_ids, gicv2_ofw_init); |