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