xref: /openbmc/linux/drivers/sh/intc/access.c (revision 0dd4d5cb)
12be6bb0cSPaul Mundt /*
22be6bb0cSPaul Mundt  * Common INTC2 register accessors
32be6bb0cSPaul Mundt  *
42be6bb0cSPaul Mundt  * Copyright (C) 2007, 2008 Magnus Damm
52be6bb0cSPaul Mundt  * Copyright (C) 2009, 2010 Paul Mundt
62be6bb0cSPaul Mundt  *
72be6bb0cSPaul Mundt  * This file is subject to the terms and conditions of the GNU General Public
82be6bb0cSPaul Mundt  * License.  See the file "COPYING" in the main directory of this archive
92be6bb0cSPaul Mundt  * for more details.
102be6bb0cSPaul Mundt  */
112be6bb0cSPaul Mundt #include <linux/io.h>
122be6bb0cSPaul Mundt #include "internals.h"
132be6bb0cSPaul Mundt 
intc_phys_to_virt(struct intc_desc_int * d,unsigned long address)142be6bb0cSPaul Mundt unsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
152be6bb0cSPaul Mundt {
162be6bb0cSPaul Mundt 	struct intc_window *window;
172be6bb0cSPaul Mundt 	int k;
182be6bb0cSPaul Mundt 
192be6bb0cSPaul Mundt 	/* scan through physical windows and convert address */
202be6bb0cSPaul Mundt 	for (k = 0; k < d->nr_windows; k++) {
212be6bb0cSPaul Mundt 		window = d->window + k;
222be6bb0cSPaul Mundt 
232be6bb0cSPaul Mundt 		if (address < window->phys)
242be6bb0cSPaul Mundt 			continue;
252be6bb0cSPaul Mundt 
262be6bb0cSPaul Mundt 		if (address >= (window->phys + window->size))
272be6bb0cSPaul Mundt 			continue;
282be6bb0cSPaul Mundt 
292be6bb0cSPaul Mundt 		address -= window->phys;
302be6bb0cSPaul Mundt 		address += (unsigned long)window->virt;
312be6bb0cSPaul Mundt 
322be6bb0cSPaul Mundt 		return address;
332be6bb0cSPaul Mundt 	}
342be6bb0cSPaul Mundt 
352be6bb0cSPaul Mundt 	/* no windows defined, register must be 1:1 mapped virt:phys */
362be6bb0cSPaul Mundt 	return address;
372be6bb0cSPaul Mundt }
382be6bb0cSPaul Mundt 
intc_get_reg(struct intc_desc_int * d,unsigned long address)392be6bb0cSPaul Mundt unsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
402be6bb0cSPaul Mundt {
412be6bb0cSPaul Mundt 	unsigned int k;
422be6bb0cSPaul Mundt 
432be6bb0cSPaul Mundt 	address = intc_phys_to_virt(d, address);
442be6bb0cSPaul Mundt 
452be6bb0cSPaul Mundt 	for (k = 0; k < d->nr_reg; k++) {
462be6bb0cSPaul Mundt 		if (d->reg[k] == address)
472be6bb0cSPaul Mundt 			return k;
482be6bb0cSPaul Mundt 	}
492be6bb0cSPaul Mundt 
502be6bb0cSPaul Mundt 	BUG();
512be6bb0cSPaul Mundt 	return 0;
522be6bb0cSPaul Mundt }
532be6bb0cSPaul Mundt 
intc_set_field_from_handle(unsigned int value,unsigned int field_value,unsigned int handle)542be6bb0cSPaul Mundt unsigned int intc_set_field_from_handle(unsigned int value,
552be6bb0cSPaul Mundt 					unsigned int field_value,
562be6bb0cSPaul Mundt 					unsigned int handle)
572be6bb0cSPaul Mundt {
582be6bb0cSPaul Mundt 	unsigned int width = _INTC_WIDTH(handle);
592be6bb0cSPaul Mundt 	unsigned int shift = _INTC_SHIFT(handle);
602be6bb0cSPaul Mundt 
612be6bb0cSPaul Mundt 	value &= ~(((1 << width) - 1) << shift);
622be6bb0cSPaul Mundt 	value |= field_value << shift;
632be6bb0cSPaul Mundt 	return value;
642be6bb0cSPaul Mundt }
652be6bb0cSPaul Mundt 
intc_get_field_from_handle(unsigned int value,unsigned int handle)662be6bb0cSPaul Mundt unsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
672be6bb0cSPaul Mundt {
682be6bb0cSPaul Mundt 	unsigned int width = _INTC_WIDTH(handle);
692be6bb0cSPaul Mundt 	unsigned int shift = _INTC_SHIFT(handle);
702be6bb0cSPaul Mundt 	unsigned int mask = ((1 << width) - 1) << shift;
712be6bb0cSPaul Mundt 
722be6bb0cSPaul Mundt 	return (value & mask) >> shift;
732be6bb0cSPaul Mundt }
742be6bb0cSPaul Mundt 
test_8(unsigned long addr,unsigned long h,unsigned long ignore)752be6bb0cSPaul Mundt static unsigned long test_8(unsigned long addr, unsigned long h,
762be6bb0cSPaul Mundt 			    unsigned long ignore)
772be6bb0cSPaul Mundt {
780dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
790dd4d5cbSPaul Mundt 	return intc_get_field_from_handle(__raw_readb(ptr), h);
802be6bb0cSPaul Mundt }
812be6bb0cSPaul Mundt 
test_16(unsigned long addr,unsigned long h,unsigned long ignore)822be6bb0cSPaul Mundt static unsigned long test_16(unsigned long addr, unsigned long h,
832be6bb0cSPaul Mundt 			     unsigned long ignore)
842be6bb0cSPaul Mundt {
850dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
860dd4d5cbSPaul Mundt 	return intc_get_field_from_handle(__raw_readw(ptr), h);
872be6bb0cSPaul Mundt }
882be6bb0cSPaul Mundt 
test_32(unsigned long addr,unsigned long h,unsigned long ignore)892be6bb0cSPaul Mundt static unsigned long test_32(unsigned long addr, unsigned long h,
902be6bb0cSPaul Mundt 			     unsigned long ignore)
912be6bb0cSPaul Mundt {
920dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
930dd4d5cbSPaul Mundt 	return intc_get_field_from_handle(__raw_readl(ptr), h);
942be6bb0cSPaul Mundt }
952be6bb0cSPaul Mundt 
write_8(unsigned long addr,unsigned long h,unsigned long data)962be6bb0cSPaul Mundt static unsigned long write_8(unsigned long addr, unsigned long h,
972be6bb0cSPaul Mundt 			     unsigned long data)
982be6bb0cSPaul Mundt {
990dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1000dd4d5cbSPaul Mundt 	__raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
1010dd4d5cbSPaul Mundt 	(void)__raw_readb(ptr);	/* Defeat write posting */
1022be6bb0cSPaul Mundt 	return 0;
1032be6bb0cSPaul Mundt }
1042be6bb0cSPaul Mundt 
write_16(unsigned long addr,unsigned long h,unsigned long data)1052be6bb0cSPaul Mundt static unsigned long write_16(unsigned long addr, unsigned long h,
1062be6bb0cSPaul Mundt 			      unsigned long data)
1072be6bb0cSPaul Mundt {
1080dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1090dd4d5cbSPaul Mundt 	__raw_writew(intc_set_field_from_handle(0, data, h), ptr);
1100dd4d5cbSPaul Mundt 	(void)__raw_readw(ptr);	/* Defeat write posting */
1112be6bb0cSPaul Mundt 	return 0;
1122be6bb0cSPaul Mundt }
1132be6bb0cSPaul Mundt 
write_32(unsigned long addr,unsigned long h,unsigned long data)1142be6bb0cSPaul Mundt static unsigned long write_32(unsigned long addr, unsigned long h,
1152be6bb0cSPaul Mundt 			      unsigned long data)
1162be6bb0cSPaul Mundt {
1170dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1180dd4d5cbSPaul Mundt 	__raw_writel(intc_set_field_from_handle(0, data, h), ptr);
1190dd4d5cbSPaul Mundt 	(void)__raw_readl(ptr);	/* Defeat write posting */
1202be6bb0cSPaul Mundt 	return 0;
1212be6bb0cSPaul Mundt }
1222be6bb0cSPaul Mundt 
modify_8(unsigned long addr,unsigned long h,unsigned long data)1232be6bb0cSPaul Mundt static unsigned long modify_8(unsigned long addr, unsigned long h,
1242be6bb0cSPaul Mundt 			      unsigned long data)
1252be6bb0cSPaul Mundt {
1260dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1272be6bb0cSPaul Mundt 	unsigned long flags;
1282be6bb0cSPaul Mundt 	unsigned int value;
1292be6bb0cSPaul Mundt 	local_irq_save(flags);
1300dd4d5cbSPaul Mundt 	value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
1310dd4d5cbSPaul Mundt 	__raw_writeb(value, ptr);
1320dd4d5cbSPaul Mundt 	(void)__raw_readb(ptr);	/* Defeat write posting */
1332be6bb0cSPaul Mundt 	local_irq_restore(flags);
1342be6bb0cSPaul Mundt 	return 0;
1352be6bb0cSPaul Mundt }
1362be6bb0cSPaul Mundt 
modify_16(unsigned long addr,unsigned long h,unsigned long data)1372be6bb0cSPaul Mundt static unsigned long modify_16(unsigned long addr, unsigned long h,
1382be6bb0cSPaul Mundt 			       unsigned long data)
1392be6bb0cSPaul Mundt {
1400dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1412be6bb0cSPaul Mundt 	unsigned long flags;
1422be6bb0cSPaul Mundt 	unsigned int value;
1432be6bb0cSPaul Mundt 	local_irq_save(flags);
1440dd4d5cbSPaul Mundt 	value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
1450dd4d5cbSPaul Mundt 	__raw_writew(value, ptr);
1460dd4d5cbSPaul Mundt 	(void)__raw_readw(ptr);	/* Defeat write posting */
1472be6bb0cSPaul Mundt 	local_irq_restore(flags);
1482be6bb0cSPaul Mundt 	return 0;
1492be6bb0cSPaul Mundt }
1502be6bb0cSPaul Mundt 
modify_32(unsigned long addr,unsigned long h,unsigned long data)1512be6bb0cSPaul Mundt static unsigned long modify_32(unsigned long addr, unsigned long h,
1522be6bb0cSPaul Mundt 			       unsigned long data)
1532be6bb0cSPaul Mundt {
1540dd4d5cbSPaul Mundt 	void __iomem *ptr = (void __iomem *)addr;
1552be6bb0cSPaul Mundt 	unsigned long flags;
1562be6bb0cSPaul Mundt 	unsigned int value;
1572be6bb0cSPaul Mundt 	local_irq_save(flags);
1580dd4d5cbSPaul Mundt 	value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
1590dd4d5cbSPaul Mundt 	__raw_writel(value, ptr);
1600dd4d5cbSPaul Mundt 	(void)__raw_readl(ptr);	/* Defeat write posting */
1612be6bb0cSPaul Mundt 	local_irq_restore(flags);
1622be6bb0cSPaul Mundt 	return 0;
1632be6bb0cSPaul Mundt }
1642be6bb0cSPaul Mundt 
intc_mode_field(unsigned long addr,unsigned long handle,unsigned long (* fn)(unsigned long,unsigned long,unsigned long),unsigned int irq)1652be6bb0cSPaul Mundt static unsigned long intc_mode_field(unsigned long addr,
1662be6bb0cSPaul Mundt 				     unsigned long handle,
1672be6bb0cSPaul Mundt 				     unsigned long (*fn)(unsigned long,
1682be6bb0cSPaul Mundt 						unsigned long,
1692be6bb0cSPaul Mundt 						unsigned long),
1702be6bb0cSPaul Mundt 				     unsigned int irq)
1712be6bb0cSPaul Mundt {
1722be6bb0cSPaul Mundt 	return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
1732be6bb0cSPaul Mundt }
1742be6bb0cSPaul Mundt 
intc_mode_zero(unsigned long addr,unsigned long handle,unsigned long (* fn)(unsigned long,unsigned long,unsigned long),unsigned int irq)1752be6bb0cSPaul Mundt static unsigned long intc_mode_zero(unsigned long addr,
1762be6bb0cSPaul Mundt 				    unsigned long handle,
1772be6bb0cSPaul Mundt 				    unsigned long (*fn)(unsigned long,
1782be6bb0cSPaul Mundt 					       unsigned long,
1792be6bb0cSPaul Mundt 					       unsigned long),
1802be6bb0cSPaul Mundt 				    unsigned int irq)
1812be6bb0cSPaul Mundt {
1822be6bb0cSPaul Mundt 	return fn(addr, handle, 0);
1832be6bb0cSPaul Mundt }
1842be6bb0cSPaul Mundt 
intc_mode_prio(unsigned long addr,unsigned long handle,unsigned long (* fn)(unsigned long,unsigned long,unsigned long),unsigned int irq)1852be6bb0cSPaul Mundt static unsigned long intc_mode_prio(unsigned long addr,
1862be6bb0cSPaul Mundt 				    unsigned long handle,
1872be6bb0cSPaul Mundt 				    unsigned long (*fn)(unsigned long,
1882be6bb0cSPaul Mundt 					       unsigned long,
1892be6bb0cSPaul Mundt 					       unsigned long),
1902be6bb0cSPaul Mundt 				    unsigned int irq)
1912be6bb0cSPaul Mundt {
1922be6bb0cSPaul Mundt 	return fn(addr, handle, intc_get_prio_level(irq));
1932be6bb0cSPaul Mundt }
1942be6bb0cSPaul Mundt 
1952be6bb0cSPaul Mundt unsigned long (*intc_reg_fns[])(unsigned long addr,
1962be6bb0cSPaul Mundt 				unsigned long h,
1972be6bb0cSPaul Mundt 				unsigned long data) = {
1982be6bb0cSPaul Mundt 	[REG_FN_TEST_BASE + 0] = test_8,
1992be6bb0cSPaul Mundt 	[REG_FN_TEST_BASE + 1] = test_16,
2002be6bb0cSPaul Mundt 	[REG_FN_TEST_BASE + 3] = test_32,
2012be6bb0cSPaul Mundt 	[REG_FN_WRITE_BASE + 0] = write_8,
2022be6bb0cSPaul Mundt 	[REG_FN_WRITE_BASE + 1] = write_16,
2032be6bb0cSPaul Mundt 	[REG_FN_WRITE_BASE + 3] = write_32,
2042be6bb0cSPaul Mundt 	[REG_FN_MODIFY_BASE + 0] = modify_8,
2052be6bb0cSPaul Mundt 	[REG_FN_MODIFY_BASE + 1] = modify_16,
2062be6bb0cSPaul Mundt 	[REG_FN_MODIFY_BASE + 3] = modify_32,
2072be6bb0cSPaul Mundt };
2082be6bb0cSPaul Mundt 
2092be6bb0cSPaul Mundt unsigned long (*intc_enable_fns[])(unsigned long addr,
2102be6bb0cSPaul Mundt 				   unsigned long handle,
2112be6bb0cSPaul Mundt 				   unsigned long (*fn)(unsigned long,
2122be6bb0cSPaul Mundt 					    unsigned long,
2132be6bb0cSPaul Mundt 					    unsigned long),
2142be6bb0cSPaul Mundt 				   unsigned int irq) = {
2152be6bb0cSPaul Mundt 	[MODE_ENABLE_REG] = intc_mode_field,
2162be6bb0cSPaul Mundt 	[MODE_MASK_REG] = intc_mode_zero,
2172be6bb0cSPaul Mundt 	[MODE_DUAL_REG] = intc_mode_field,
2182be6bb0cSPaul Mundt 	[MODE_PRIO_REG] = intc_mode_prio,
2192be6bb0cSPaul Mundt 	[MODE_PCLR_REG] = intc_mode_prio,
2202be6bb0cSPaul Mundt };
2212be6bb0cSPaul Mundt 
2222be6bb0cSPaul Mundt unsigned long (*intc_disable_fns[])(unsigned long addr,
2232be6bb0cSPaul Mundt 				    unsigned long handle,
2242be6bb0cSPaul Mundt 				    unsigned long (*fn)(unsigned long,
2252be6bb0cSPaul Mundt 					     unsigned long,
2262be6bb0cSPaul Mundt 					     unsigned long),
2272be6bb0cSPaul Mundt 				    unsigned int irq) = {
2282be6bb0cSPaul Mundt 	[MODE_ENABLE_REG] = intc_mode_zero,
2292be6bb0cSPaul Mundt 	[MODE_MASK_REG] = intc_mode_field,
2302be6bb0cSPaul Mundt 	[MODE_DUAL_REG] = intc_mode_field,
2312be6bb0cSPaul Mundt 	[MODE_PRIO_REG] = intc_mode_zero,
2322be6bb0cSPaul Mundt 	[MODE_PCLR_REG] = intc_mode_field,
2332be6bb0cSPaul Mundt };
2342be6bb0cSPaul Mundt 
2352be6bb0cSPaul Mundt unsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
2362be6bb0cSPaul Mundt 					  unsigned long handle,
2372be6bb0cSPaul Mundt 					  unsigned long (*fn)(unsigned long,
2382be6bb0cSPaul Mundt 						unsigned long,
2392be6bb0cSPaul Mundt 						unsigned long),
2402be6bb0cSPaul Mundt 					  unsigned int irq) = {
2412be6bb0cSPaul Mundt 	[MODE_ENABLE_REG] = intc_mode_field,
2422be6bb0cSPaul Mundt 	[MODE_MASK_REG] = intc_mode_zero,
2432be6bb0cSPaul Mundt 	[MODE_DUAL_REG] = intc_mode_field,
2442be6bb0cSPaul Mundt 	[MODE_PRIO_REG] = intc_mode_field,
2452be6bb0cSPaul Mundt 	[MODE_PCLR_REG] = intc_mode_field,
2462be6bb0cSPaul Mundt };
247