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 20 static struct bcsr_reg { 21 void __iomem *raddr; 22 spinlock_t lock; 23 } bcsr_regs[BCSR_CNT]; 24 25 static void __iomem *bcsr_virt; /* KSEG1 addr of BCSR base */ 26 static int bcsr_csc_base; /* linux-irq of first cascaded irq */ 27 28 void __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 49 unsigned 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 } 59 EXPORT_SYMBOL_GPL(bcsr_read); 60 61 void 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 } 70 EXPORT_SYMBOL_GPL(bcsr_write); 71 72 void 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 } 85 EXPORT_SYMBOL_GPL(bcsr_mod); 86 87 /* 88 * DB1200/PB1200 CPLD IRQ muxer 89 */ 90 static 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 100 static 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 107 static 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 115 static 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 122 static 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 129 void __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 } 147