cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bcsr.c (3736B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
      4 *
      5 * All Alchemy development boards (except, of course, the weird PB1000)
      6 * have a few registers in a CPLD with standardised layout; they mostly
      7 * only differ in base address.
      8 * All registers are 16bits wide with 32bit spacing.
      9 */
     10
     11#include <linux/interrupt.h>
     12#include <linux/irqchip/chained_irq.h>
     13#include <linux/init.h>
     14#include <linux/export.h>
     15#include <linux/spinlock.h>
     16#include <linux/irq.h>
     17#include <asm/addrspace.h>
     18#include <asm/io.h>
     19#include <asm/mach-db1x00/bcsr.h>
     20
     21static struct bcsr_reg {
     22	void __iomem *raddr;
     23	spinlock_t lock;
     24} bcsr_regs[BCSR_CNT];
     25
     26static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */
     27static int bcsr_csc_base;	/* linux-irq of first cascaded irq */
     28
     29void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
     30{
     31	int i;
     32
     33	bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys));
     34	bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys));
     35
     36	bcsr_virt = (void __iomem *)bcsr1_phys;
     37
     38	for (i = 0; i < BCSR_CNT; i++) {
     39		if (i >= BCSR_HEXLEDS)
     40			bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys +
     41					(0x04 * (i - BCSR_HEXLEDS));
     42		else
     43			bcsr_regs[i].raddr = (void __iomem *)bcsr1_phys +
     44					(0x04 * i);
     45
     46		spin_lock_init(&bcsr_regs[i].lock);
     47	}
     48}
     49
     50unsigned short bcsr_read(enum bcsr_id reg)
     51{
     52	unsigned short r;
     53	unsigned long flags;
     54
     55	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
     56	r = __raw_readw(bcsr_regs[reg].raddr);
     57	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
     58	return r;
     59}
     60EXPORT_SYMBOL_GPL(bcsr_read);
     61
     62void bcsr_write(enum bcsr_id reg, unsigned short val)
     63{
     64	unsigned long flags;
     65
     66	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
     67	__raw_writew(val, bcsr_regs[reg].raddr);
     68	wmb();
     69	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
     70}
     71EXPORT_SYMBOL_GPL(bcsr_write);
     72
     73void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set)
     74{
     75	unsigned short r;
     76	unsigned long flags;
     77
     78	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
     79	r = __raw_readw(bcsr_regs[reg].raddr);
     80	r &= ~clr;
     81	r |= set;
     82	__raw_writew(r, bcsr_regs[reg].raddr);
     83	wmb();
     84	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
     85}
     86EXPORT_SYMBOL_GPL(bcsr_mod);
     87
     88/*
     89 * DB1200/PB1200 CPLD IRQ muxer
     90 */
     91static void bcsr_csc_handler(struct irq_desc *d)
     92{
     93	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
     94	struct irq_chip *chip = irq_desc_get_chip(d);
     95
     96	chained_irq_enter(chip, d);
     97	generic_handle_irq(bcsr_csc_base + __ffs(bisr));
     98	chained_irq_exit(chip, d);
     99}
    100
    101static void bcsr_irq_mask(struct irq_data *d)
    102{
    103	unsigned short v = 1 << (d->irq - bcsr_csc_base);
    104	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
    105	wmb();
    106}
    107
    108static void bcsr_irq_maskack(struct irq_data *d)
    109{
    110	unsigned short v = 1 << (d->irq - bcsr_csc_base);
    111	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
    112	__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);	/* ack */
    113	wmb();
    114}
    115
    116static void bcsr_irq_unmask(struct irq_data *d)
    117{
    118	unsigned short v = 1 << (d->irq - bcsr_csc_base);
    119	__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
    120	wmb();
    121}
    122
    123static struct irq_chip bcsr_irq_type = {
    124	.name		= "CPLD",
    125	.irq_mask	= bcsr_irq_mask,
    126	.irq_mask_ack	= bcsr_irq_maskack,
    127	.irq_unmask	= bcsr_irq_unmask,
    128};
    129
    130void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
    131{
    132	unsigned int irq;
    133
    134	/* mask & enable & ack all */
    135	__raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
    136	__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSET);
    137	__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
    138	wmb();
    139
    140	bcsr_csc_base = csc_start;
    141
    142	for (irq = csc_start; irq <= csc_end; irq++)
    143		irq_set_chip_and_handler_name(irq, &bcsr_irq_type,
    144					      handle_level_irq, "level");
    145
    146	irq_set_chained_handler(hook_irq, bcsr_csc_handler);
    147}