1*2be6bb0cSPaul Mundt /* 2*2be6bb0cSPaul Mundt * Common INTC2 register accessors 3*2be6bb0cSPaul Mundt * 4*2be6bb0cSPaul Mundt * Copyright (C) 2007, 2008 Magnus Damm 5*2be6bb0cSPaul Mundt * Copyright (C) 2009, 2010 Paul Mundt 6*2be6bb0cSPaul Mundt * 7*2be6bb0cSPaul Mundt * This file is subject to the terms and conditions of the GNU General Public 8*2be6bb0cSPaul Mundt * License. See the file "COPYING" in the main directory of this archive 9*2be6bb0cSPaul Mundt * for more details. 10*2be6bb0cSPaul Mundt */ 11*2be6bb0cSPaul Mundt #include <linux/io.h> 12*2be6bb0cSPaul Mundt #include "internals.h" 13*2be6bb0cSPaul Mundt 14*2be6bb0cSPaul Mundt unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address) 15*2be6bb0cSPaul Mundt { 16*2be6bb0cSPaul Mundt struct intc_window *window; 17*2be6bb0cSPaul Mundt int k; 18*2be6bb0cSPaul Mundt 19*2be6bb0cSPaul Mundt /* scan through physical windows and convert address */ 20*2be6bb0cSPaul Mundt for (k = 0; k < d->nr_windows; k++) { 21*2be6bb0cSPaul Mundt window = d->window + k; 22*2be6bb0cSPaul Mundt 23*2be6bb0cSPaul Mundt if (address < window->phys) 24*2be6bb0cSPaul Mundt continue; 25*2be6bb0cSPaul Mundt 26*2be6bb0cSPaul Mundt if (address >= (window->phys + window->size)) 27*2be6bb0cSPaul Mundt continue; 28*2be6bb0cSPaul Mundt 29*2be6bb0cSPaul Mundt address -= window->phys; 30*2be6bb0cSPaul Mundt address += (unsigned long)window->virt; 31*2be6bb0cSPaul Mundt 32*2be6bb0cSPaul Mundt return address; 33*2be6bb0cSPaul Mundt } 34*2be6bb0cSPaul Mundt 35*2be6bb0cSPaul Mundt /* no windows defined, register must be 1:1 mapped virt:phys */ 36*2be6bb0cSPaul Mundt return address; 37*2be6bb0cSPaul Mundt } 38*2be6bb0cSPaul Mundt 39*2be6bb0cSPaul Mundt unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address) 40*2be6bb0cSPaul Mundt { 41*2be6bb0cSPaul Mundt unsigned int k; 42*2be6bb0cSPaul Mundt 43*2be6bb0cSPaul Mundt address = intc_phys_to_virt(d, address); 44*2be6bb0cSPaul Mundt 45*2be6bb0cSPaul Mundt for (k = 0; k < d->nr_reg; k++) { 46*2be6bb0cSPaul Mundt if (d->reg[k] == address) 47*2be6bb0cSPaul Mundt return k; 48*2be6bb0cSPaul Mundt } 49*2be6bb0cSPaul Mundt 50*2be6bb0cSPaul Mundt BUG(); 51*2be6bb0cSPaul Mundt return 0; 52*2be6bb0cSPaul Mundt } 53*2be6bb0cSPaul Mundt 54*2be6bb0cSPaul Mundt unsigned int intc_set_field_from_handle(unsigned int value, 55*2be6bb0cSPaul Mundt unsigned int field_value, 56*2be6bb0cSPaul Mundt unsigned int handle) 57*2be6bb0cSPaul Mundt { 58*2be6bb0cSPaul Mundt unsigned int width = _INTC_WIDTH(handle); 59*2be6bb0cSPaul Mundt unsigned int shift = _INTC_SHIFT(handle); 60*2be6bb0cSPaul Mundt 61*2be6bb0cSPaul Mundt value &= ~(((1 << width) - 1) << shift); 62*2be6bb0cSPaul Mundt value |= field_value << shift; 63*2be6bb0cSPaul Mundt return value; 64*2be6bb0cSPaul Mundt } 65*2be6bb0cSPaul Mundt 66*2be6bb0cSPaul Mundt unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle) 67*2be6bb0cSPaul Mundt { 68*2be6bb0cSPaul Mundt unsigned int width = _INTC_WIDTH(handle); 69*2be6bb0cSPaul Mundt unsigned int shift = _INTC_SHIFT(handle); 70*2be6bb0cSPaul Mundt unsigned int mask = ((1 << width) - 1) << shift; 71*2be6bb0cSPaul Mundt 72*2be6bb0cSPaul Mundt return (value & mask) >> shift; 73*2be6bb0cSPaul Mundt } 74*2be6bb0cSPaul Mundt 75*2be6bb0cSPaul Mundt static unsigned long test_8(unsigned long addr, unsigned long h, 76*2be6bb0cSPaul Mundt unsigned long ignore) 77*2be6bb0cSPaul Mundt { 78*2be6bb0cSPaul Mundt return intc_get_field_from_handle(__raw_readb(addr), h); 79*2be6bb0cSPaul Mundt } 80*2be6bb0cSPaul Mundt 81*2be6bb0cSPaul Mundt static unsigned long test_16(unsigned long addr, unsigned long h, 82*2be6bb0cSPaul Mundt unsigned long ignore) 83*2be6bb0cSPaul Mundt { 84*2be6bb0cSPaul Mundt return intc_get_field_from_handle(__raw_readw(addr), h); 85*2be6bb0cSPaul Mundt } 86*2be6bb0cSPaul Mundt 87*2be6bb0cSPaul Mundt static unsigned long test_32(unsigned long addr, unsigned long h, 88*2be6bb0cSPaul Mundt unsigned long ignore) 89*2be6bb0cSPaul Mundt { 90*2be6bb0cSPaul Mundt return intc_get_field_from_handle(__raw_readl(addr), h); 91*2be6bb0cSPaul Mundt } 92*2be6bb0cSPaul Mundt 93*2be6bb0cSPaul Mundt static unsigned long write_8(unsigned long addr, unsigned long h, 94*2be6bb0cSPaul Mundt unsigned long data) 95*2be6bb0cSPaul Mundt { 96*2be6bb0cSPaul Mundt __raw_writeb(intc_set_field_from_handle(0, data, h), addr); 97*2be6bb0cSPaul Mundt (void)__raw_readb(addr); /* Defeat write posting */ 98*2be6bb0cSPaul Mundt return 0; 99*2be6bb0cSPaul Mundt } 100*2be6bb0cSPaul Mundt 101*2be6bb0cSPaul Mundt static unsigned long write_16(unsigned long addr, unsigned long h, 102*2be6bb0cSPaul Mundt unsigned long data) 103*2be6bb0cSPaul Mundt { 104*2be6bb0cSPaul Mundt __raw_writew(intc_set_field_from_handle(0, data, h), addr); 105*2be6bb0cSPaul Mundt (void)__raw_readw(addr); /* Defeat write posting */ 106*2be6bb0cSPaul Mundt return 0; 107*2be6bb0cSPaul Mundt } 108*2be6bb0cSPaul Mundt 109*2be6bb0cSPaul Mundt static unsigned long write_32(unsigned long addr, unsigned long h, 110*2be6bb0cSPaul Mundt unsigned long data) 111*2be6bb0cSPaul Mundt { 112*2be6bb0cSPaul Mundt __raw_writel(intc_set_field_from_handle(0, data, h), addr); 113*2be6bb0cSPaul Mundt (void)__raw_readl(addr); /* Defeat write posting */ 114*2be6bb0cSPaul Mundt return 0; 115*2be6bb0cSPaul Mundt } 116*2be6bb0cSPaul Mundt 117*2be6bb0cSPaul Mundt static unsigned long modify_8(unsigned long addr, unsigned long h, 118*2be6bb0cSPaul Mundt unsigned long data) 119*2be6bb0cSPaul Mundt { 120*2be6bb0cSPaul Mundt unsigned long flags; 121*2be6bb0cSPaul Mundt unsigned int value; 122*2be6bb0cSPaul Mundt local_irq_save(flags); 123*2be6bb0cSPaul Mundt value = intc_set_field_from_handle(__raw_readb(addr), data, h); 124*2be6bb0cSPaul Mundt __raw_writeb(value, addr); 125*2be6bb0cSPaul Mundt (void)__raw_readb(addr); /* Defeat write posting */ 126*2be6bb0cSPaul Mundt local_irq_restore(flags); 127*2be6bb0cSPaul Mundt return 0; 128*2be6bb0cSPaul Mundt } 129*2be6bb0cSPaul Mundt 130*2be6bb0cSPaul Mundt static unsigned long modify_16(unsigned long addr, unsigned long h, 131*2be6bb0cSPaul Mundt unsigned long data) 132*2be6bb0cSPaul Mundt { 133*2be6bb0cSPaul Mundt unsigned long flags; 134*2be6bb0cSPaul Mundt unsigned int value; 135*2be6bb0cSPaul Mundt local_irq_save(flags); 136*2be6bb0cSPaul Mundt value = intc_set_field_from_handle(__raw_readw(addr), data, h); 137*2be6bb0cSPaul Mundt __raw_writew(value, addr); 138*2be6bb0cSPaul Mundt (void)__raw_readw(addr); /* Defeat write posting */ 139*2be6bb0cSPaul Mundt local_irq_restore(flags); 140*2be6bb0cSPaul Mundt return 0; 141*2be6bb0cSPaul Mundt } 142*2be6bb0cSPaul Mundt 143*2be6bb0cSPaul Mundt static unsigned long modify_32(unsigned long addr, unsigned long h, 144*2be6bb0cSPaul Mundt unsigned long data) 145*2be6bb0cSPaul Mundt { 146*2be6bb0cSPaul Mundt unsigned long flags; 147*2be6bb0cSPaul Mundt unsigned int value; 148*2be6bb0cSPaul Mundt local_irq_save(flags); 149*2be6bb0cSPaul Mundt value = intc_set_field_from_handle(__raw_readl(addr), data, h); 150*2be6bb0cSPaul Mundt __raw_writel(value, addr); 151*2be6bb0cSPaul Mundt (void)__raw_readl(addr); /* Defeat write posting */ 152*2be6bb0cSPaul Mundt local_irq_restore(flags); 153*2be6bb0cSPaul Mundt return 0; 154*2be6bb0cSPaul Mundt } 155*2be6bb0cSPaul Mundt 156*2be6bb0cSPaul Mundt static unsigned long intc_mode_field(unsigned long addr, 157*2be6bb0cSPaul Mundt unsigned long handle, 158*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 159*2be6bb0cSPaul Mundt unsigned long, 160*2be6bb0cSPaul Mundt unsigned long), 161*2be6bb0cSPaul Mundt unsigned int irq) 162*2be6bb0cSPaul Mundt { 163*2be6bb0cSPaul Mundt return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1)); 164*2be6bb0cSPaul Mundt } 165*2be6bb0cSPaul Mundt 166*2be6bb0cSPaul Mundt static unsigned long intc_mode_zero(unsigned long addr, 167*2be6bb0cSPaul Mundt unsigned long handle, 168*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 169*2be6bb0cSPaul Mundt unsigned long, 170*2be6bb0cSPaul Mundt unsigned long), 171*2be6bb0cSPaul Mundt unsigned int irq) 172*2be6bb0cSPaul Mundt { 173*2be6bb0cSPaul Mundt return fn(addr, handle, 0); 174*2be6bb0cSPaul Mundt } 175*2be6bb0cSPaul Mundt 176*2be6bb0cSPaul Mundt static unsigned long intc_mode_prio(unsigned long addr, 177*2be6bb0cSPaul Mundt unsigned long handle, 178*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 179*2be6bb0cSPaul Mundt unsigned long, 180*2be6bb0cSPaul Mundt unsigned long), 181*2be6bb0cSPaul Mundt unsigned int irq) 182*2be6bb0cSPaul Mundt { 183*2be6bb0cSPaul Mundt return fn(addr, handle, intc_get_prio_level(irq)); 184*2be6bb0cSPaul Mundt } 185*2be6bb0cSPaul Mundt 186*2be6bb0cSPaul Mundt unsigned long (*intc_reg_fns[])(unsigned long addr, 187*2be6bb0cSPaul Mundt unsigned long h, 188*2be6bb0cSPaul Mundt unsigned long data) = { 189*2be6bb0cSPaul Mundt [REG_FN_TEST_BASE + 0] = test_8, 190*2be6bb0cSPaul Mundt [REG_FN_TEST_BASE + 1] = test_16, 191*2be6bb0cSPaul Mundt [REG_FN_TEST_BASE + 3] = test_32, 192*2be6bb0cSPaul Mundt [REG_FN_WRITE_BASE + 0] = write_8, 193*2be6bb0cSPaul Mundt [REG_FN_WRITE_BASE + 1] = write_16, 194*2be6bb0cSPaul Mundt [REG_FN_WRITE_BASE + 3] = write_32, 195*2be6bb0cSPaul Mundt [REG_FN_MODIFY_BASE + 0] = modify_8, 196*2be6bb0cSPaul Mundt [REG_FN_MODIFY_BASE + 1] = modify_16, 197*2be6bb0cSPaul Mundt [REG_FN_MODIFY_BASE + 3] = modify_32, 198*2be6bb0cSPaul Mundt }; 199*2be6bb0cSPaul Mundt 200*2be6bb0cSPaul Mundt unsigned long (*intc_enable_fns[])(unsigned long addr, 201*2be6bb0cSPaul Mundt unsigned long handle, 202*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 203*2be6bb0cSPaul Mundt unsigned long, 204*2be6bb0cSPaul Mundt unsigned long), 205*2be6bb0cSPaul Mundt unsigned int irq) = { 206*2be6bb0cSPaul Mundt [MODE_ENABLE_REG] = intc_mode_field, 207*2be6bb0cSPaul Mundt [MODE_MASK_REG] = intc_mode_zero, 208*2be6bb0cSPaul Mundt [MODE_DUAL_REG] = intc_mode_field, 209*2be6bb0cSPaul Mundt [MODE_PRIO_REG] = intc_mode_prio, 210*2be6bb0cSPaul Mundt [MODE_PCLR_REG] = intc_mode_prio, 211*2be6bb0cSPaul Mundt }; 212*2be6bb0cSPaul Mundt 213*2be6bb0cSPaul Mundt unsigned long (*intc_disable_fns[])(unsigned long addr, 214*2be6bb0cSPaul Mundt unsigned long handle, 215*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 216*2be6bb0cSPaul Mundt unsigned long, 217*2be6bb0cSPaul Mundt unsigned long), 218*2be6bb0cSPaul Mundt unsigned int irq) = { 219*2be6bb0cSPaul Mundt [MODE_ENABLE_REG] = intc_mode_zero, 220*2be6bb0cSPaul Mundt [MODE_MASK_REG] = intc_mode_field, 221*2be6bb0cSPaul Mundt [MODE_DUAL_REG] = intc_mode_field, 222*2be6bb0cSPaul Mundt [MODE_PRIO_REG] = intc_mode_zero, 223*2be6bb0cSPaul Mundt [MODE_PCLR_REG] = intc_mode_field, 224*2be6bb0cSPaul Mundt }; 225*2be6bb0cSPaul Mundt 226*2be6bb0cSPaul Mundt unsigned long (*intc_enable_noprio_fns[])(unsigned long addr, 227*2be6bb0cSPaul Mundt unsigned long handle, 228*2be6bb0cSPaul Mundt unsigned long (*fn)(unsigned long, 229*2be6bb0cSPaul Mundt unsigned long, 230*2be6bb0cSPaul Mundt unsigned long), 231*2be6bb0cSPaul Mundt unsigned int irq) = { 232*2be6bb0cSPaul Mundt [MODE_ENABLE_REG] = intc_mode_field, 233*2be6bb0cSPaul Mundt [MODE_MASK_REG] = intc_mode_zero, 234*2be6bb0cSPaul Mundt [MODE_DUAL_REG] = intc_mode_field, 235*2be6bb0cSPaul Mundt [MODE_PRIO_REG] = intc_mode_field, 236*2be6bb0cSPaul Mundt [MODE_PCLR_REG] = intc_mode_field, 237*2be6bb0cSPaul Mundt }; 238