Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/irqchip/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  irq-mxs.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
 * Copyright (C) 2014 Oleksij Rempel <linux@rempel-privat.de>
 * Add Alphascale ASM9260 support.
 */


#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/stmp_device.h>
#include <asm/exception.h>

#include "alphascale_asm9260-icoll.h"

/*
 * this device provide 4 offsets for each register:
 * 0x0 - plain read write mode
 * 0x4 - set mode, OR logic.
 * 0x8 - clr mode, XOR logic.
 * 0xc - togle mode.
 */

#define SET_REG 4
#define CLR_REG 8

#define HW_ICOLL_VECTOR    0x0000
#define HW_ICOLL_LEVELACK   0x0010
#define HW_ICOLL_CTRL    0x0020
#define HW_ICOLL_STAT_OFFSET   0x0070
#define HW_ICOLL_INTERRUPT0   0x0120
#define HW_ICOLL_INTERRUPTn(n)   ((n) * 0x10)
#define BM_ICOLL_INTR_ENABLE   BIT(2)
#define BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 0x1

#define ICOLL_NUM_IRQS  128

enum icoll_type {
 ICOLL,
 ASM9260_ICOLL,
};

struct icoll_priv {
 void __iomem *vector;
 void __iomem *levelack;
 void __iomem *ctrl;
 void __iomem *stat;
 void __iomem *intr;
 void __iomem *clear;
 enum icoll_type type;
};

static struct icoll_priv icoll_priv;
static struct irq_domain *icoll_domain;

/* calculate bit offset depending on number of interrupt per register */
static u32 icoll_intr_bitshift(struct irq_data *d, u32 bit)
{
 /*
 * mask lower part of hwirq to convert it
 * in 0, 1, 2 or 3 and then multiply it by 8 (or shift by 3)
 */

 return bit << ((d->hwirq & 3) << 3);
}

/* calculate mem offset depending on number of interrupt per register */
static void __iomem *icoll_intr_reg(struct irq_data *d)
{
 /* offset = hwirq / intr_per_reg * 0x10 */
 return icoll_priv.intr + ((d->hwirq >> 2) * 0x10);
}

static void icoll_ack_irq(struct irq_data *d)
{
 /*
 * The Interrupt Collector is able to prioritize irqs.
 * Currently only level 0 is used. So acking can use
 * BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0 unconditionally.
 */

 __raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
   icoll_priv.levelack);
}

static void icoll_mask_irq(struct irq_data *d)
{
 __raw_writel(BM_ICOLL_INTR_ENABLE,
   icoll_priv.intr + CLR_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
}

static void icoll_unmask_irq(struct irq_data *d)
{
 __raw_writel(BM_ICOLL_INTR_ENABLE,
   icoll_priv.intr + SET_REG + HW_ICOLL_INTERRUPTn(d->hwirq));
}

static void asm9260_mask_irq(struct irq_data *d)
{
 __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE),
   icoll_intr_reg(d) + CLR_REG);
}

static void asm9260_unmask_irq(struct irq_data *d)
{
 __raw_writel(ASM9260_BM_CLEAR_BIT(d->hwirq),
       icoll_priv.clear +
       ASM9260_HW_ICOLL_CLEARn(d->hwirq));

 __raw_writel(icoll_intr_bitshift(d, BM_ICOLL_INTR_ENABLE),
   icoll_intr_reg(d) + SET_REG);
}

static struct irq_chip mxs_icoll_chip = {
 .irq_ack = icoll_ack_irq,
 .irq_mask = icoll_mask_irq,
 .irq_unmask = icoll_unmask_irq,
 .flags = IRQCHIP_MASK_ON_SUSPEND |
   IRQCHIP_SKIP_SET_WAKE,
};

static struct irq_chip asm9260_icoll_chip = {
 .irq_ack = icoll_ack_irq,
 .irq_mask = asm9260_mask_irq,
 .irq_unmask = asm9260_unmask_irq,
 .flags = IRQCHIP_MASK_ON_SUSPEND |
   IRQCHIP_SKIP_SET_WAKE,
};

static void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
{
 u32 irqnr;

 irqnr = __raw_readl(icoll_priv.stat);
 __raw_writel(irqnr, icoll_priv.vector);
 generic_handle_domain_irq(icoll_domain, irqnr);
}

static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
    irq_hw_number_t hw)
{
 struct irq_chip *chip;

 if (icoll_priv.type == ICOLL)
  chip = &mxs_icoll_chip;
 else
  chip = &asm9260_icoll_chip;

 irq_set_chip_and_handler(virq, chip, handle_level_irq);

 return 0;
}

static const struct irq_domain_ops icoll_irq_domain_ops = {
 .map = icoll_irq_domain_map,
 .xlate = irq_domain_xlate_onecell,
};

static void __init icoll_add_domain(struct device_node *np,
     int num)
{
 icoll_domain = irq_domain_create_linear(of_fwnode_handle(np), num,
      &icoll_irq_domain_ops, NULL);

 if (!icoll_domain)
  panic("%pOF: unable to create irq domain", np);
}

static void __iomem * __init icoll_init_iobase(struct device_node *np)
{
 void __iomem *icoll_base;

 icoll_base = of_io_request_and_map(np, 0, np->name);
 if (IS_ERR(icoll_base))
  panic("%pOF: unable to map resource", np);
 return icoll_base;
}

static int __init icoll_of_init(struct device_node *np,
     struct device_node *interrupt_parent)
{
 void __iomem *icoll_base;

 icoll_priv.type = ICOLL;

 icoll_base  = icoll_init_iobase(np);
 icoll_priv.vector = icoll_base + HW_ICOLL_VECTOR;
 icoll_priv.levelack = icoll_base + HW_ICOLL_LEVELACK;
 icoll_priv.ctrl  = icoll_base + HW_ICOLL_CTRL;
 icoll_priv.stat  = icoll_base + HW_ICOLL_STAT_OFFSET;
 icoll_priv.intr  = icoll_base + HW_ICOLL_INTERRUPT0;
 icoll_priv.clear = NULL;

 /*
 * Interrupt Collector reset, which initializes the priority
 * for each irq to level 0.
 */

 stmp_reset_block(icoll_priv.ctrl);

 icoll_add_domain(np, ICOLL_NUM_IRQS);
 set_handle_irq(icoll_handle_irq);

 return 0;
}
IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init);

static int __init asm9260_of_init(struct device_node *np,
     struct device_node *interrupt_parent)
{
 void __iomem *icoll_base;
 int i;

 icoll_priv.type = ASM9260_ICOLL;

 icoll_base = icoll_init_iobase(np);
 icoll_priv.vector = icoll_base + ASM9260_HW_ICOLL_VECTOR;
 icoll_priv.levelack = icoll_base + ASM9260_HW_ICOLL_LEVELACK;
 icoll_priv.ctrl  = icoll_base + ASM9260_HW_ICOLL_CTRL;
 icoll_priv.stat  = icoll_base + ASM9260_HW_ICOLL_STAT_OFFSET;
 icoll_priv.intr  = icoll_base + ASM9260_HW_ICOLL_INTERRUPT0;
 icoll_priv.clear = icoll_base + ASM9260_HW_ICOLL_CLEAR0;

 writel_relaxed(ASM9260_BM_CTRL_IRQ_ENABLE,
   icoll_priv.ctrl);
 /*
 * ASM9260 don't provide reset bit. So, we need to set level 0
 * manually.
 */

 for (i = 0; i < 16 * 0x10; i += 0x10)
  writel(0, icoll_priv.intr + i);

 icoll_add_domain(np, ASM9260_NUM_IRQS);
 set_handle_irq(icoll_handle_irq);

 return 0;
}
IRQCHIP_DECLARE(asm9260, "alphascale,asm9260-icoll", asm9260_of_init);

Messung V0.5
C=96 H=95 G=95

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.