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