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 21 static struct bcsr_reg { 22 void __iomem *raddr; 23 spinlock_t lock; 24 } bcsr_regs[BCSR_CNT]; 25 26 static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */ 27 static int bcsr_csc_base; /* linux-irq of first cascaded irq */ 28 29 void __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 50 unsigned 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 } 60 EXPORT_SYMBOL_GPL(bcsr_read); 61 62 void 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 } 71 EXPORT_SYMBOL_GPL(bcsr_write); 72 73 void 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 } 86 EXPORT_SYMBOL_GPL(bcsr_mod); 87 88 /* 89 * DB1200/PB1200 CPLD IRQ muxer 90 */ 91 static 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 101 static 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 108 static 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 116 static 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 123 static 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 130 void __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 } 148