xref: /kernel/linux/linux-5.10/drivers/sh/intc/access.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Common INTC2 register accessors
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008 Magnus Damm
58c2ecf20Sopenharmony_ci * Copyright (C) 2009, 2010 Paul Mundt
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
88c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
98c2ecf20Sopenharmony_ci * for more details.
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci#include <linux/io.h>
128c2ecf20Sopenharmony_ci#include "internals.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciunsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	struct intc_window *window;
178c2ecf20Sopenharmony_ci	int k;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/* scan through physical windows and convert address */
208c2ecf20Sopenharmony_ci	for (k = 0; k < d->nr_windows; k++) {
218c2ecf20Sopenharmony_ci		window = d->window + k;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci		if (address < window->phys)
248c2ecf20Sopenharmony_ci			continue;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci		if (address >= (window->phys + window->size))
278c2ecf20Sopenharmony_ci			continue;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci		address -= window->phys;
308c2ecf20Sopenharmony_ci		address += (unsigned long)window->virt;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci		return address;
338c2ecf20Sopenharmony_ci	}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	/* no windows defined, register must be 1:1 mapped virt:phys */
368c2ecf20Sopenharmony_ci	return address;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ciunsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	unsigned int k;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	address = intc_phys_to_virt(d, address);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	for (k = 0; k < d->nr_reg; k++) {
468c2ecf20Sopenharmony_ci		if (d->reg[k] == address)
478c2ecf20Sopenharmony_ci			return k;
488c2ecf20Sopenharmony_ci	}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	BUG();
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciunsigned int intc_set_field_from_handle(unsigned int value,
558c2ecf20Sopenharmony_ci					unsigned int field_value,
568c2ecf20Sopenharmony_ci					unsigned int handle)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	unsigned int width = _INTC_WIDTH(handle);
598c2ecf20Sopenharmony_ci	unsigned int shift = _INTC_SHIFT(handle);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	value &= ~(((1 << width) - 1) << shift);
628c2ecf20Sopenharmony_ci	value |= field_value << shift;
638c2ecf20Sopenharmony_ci	return value;
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ciunsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	unsigned int width = _INTC_WIDTH(handle);
698c2ecf20Sopenharmony_ci	unsigned int shift = _INTC_SHIFT(handle);
708c2ecf20Sopenharmony_ci	unsigned int mask = ((1 << width) - 1) << shift;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return (value & mask) >> shift;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic unsigned long test_8(unsigned long addr, unsigned long h,
768c2ecf20Sopenharmony_ci			    unsigned long ignore)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
798c2ecf20Sopenharmony_ci	return intc_get_field_from_handle(__raw_readb(ptr), h);
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic unsigned long test_16(unsigned long addr, unsigned long h,
838c2ecf20Sopenharmony_ci			     unsigned long ignore)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
868c2ecf20Sopenharmony_ci	return intc_get_field_from_handle(__raw_readw(ptr), h);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic unsigned long test_32(unsigned long addr, unsigned long h,
908c2ecf20Sopenharmony_ci			     unsigned long ignore)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
938c2ecf20Sopenharmony_ci	return intc_get_field_from_handle(__raw_readl(ptr), h);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic unsigned long write_8(unsigned long addr, unsigned long h,
978c2ecf20Sopenharmony_ci			     unsigned long data)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1008c2ecf20Sopenharmony_ci	__raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
1018c2ecf20Sopenharmony_ci	(void)__raw_readb(ptr);	/* Defeat write posting */
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic unsigned long write_16(unsigned long addr, unsigned long h,
1068c2ecf20Sopenharmony_ci			      unsigned long data)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1098c2ecf20Sopenharmony_ci	__raw_writew(intc_set_field_from_handle(0, data, h), ptr);
1108c2ecf20Sopenharmony_ci	(void)__raw_readw(ptr);	/* Defeat write posting */
1118c2ecf20Sopenharmony_ci	return 0;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistatic unsigned long write_32(unsigned long addr, unsigned long h,
1158c2ecf20Sopenharmony_ci			      unsigned long data)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1188c2ecf20Sopenharmony_ci	__raw_writel(intc_set_field_from_handle(0, data, h), ptr);
1198c2ecf20Sopenharmony_ci	(void)__raw_readl(ptr);	/* Defeat write posting */
1208c2ecf20Sopenharmony_ci	return 0;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic unsigned long modify_8(unsigned long addr, unsigned long h,
1248c2ecf20Sopenharmony_ci			      unsigned long data)
1258c2ecf20Sopenharmony_ci{
1268c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1278c2ecf20Sopenharmony_ci	unsigned long flags;
1288c2ecf20Sopenharmony_ci	unsigned int value;
1298c2ecf20Sopenharmony_ci	local_irq_save(flags);
1308c2ecf20Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
1318c2ecf20Sopenharmony_ci	__raw_writeb(value, ptr);
1328c2ecf20Sopenharmony_ci	(void)__raw_readb(ptr);	/* Defeat write posting */
1338c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1348c2ecf20Sopenharmony_ci	return 0;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic unsigned long modify_16(unsigned long addr, unsigned long h,
1388c2ecf20Sopenharmony_ci			       unsigned long data)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1418c2ecf20Sopenharmony_ci	unsigned long flags;
1428c2ecf20Sopenharmony_ci	unsigned int value;
1438c2ecf20Sopenharmony_ci	local_irq_save(flags);
1448c2ecf20Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
1458c2ecf20Sopenharmony_ci	__raw_writew(value, ptr);
1468c2ecf20Sopenharmony_ci	(void)__raw_readw(ptr);	/* Defeat write posting */
1478c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1488c2ecf20Sopenharmony_ci	return 0;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic unsigned long modify_32(unsigned long addr, unsigned long h,
1528c2ecf20Sopenharmony_ci			       unsigned long data)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
1558c2ecf20Sopenharmony_ci	unsigned long flags;
1568c2ecf20Sopenharmony_ci	unsigned int value;
1578c2ecf20Sopenharmony_ci	local_irq_save(flags);
1588c2ecf20Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
1598c2ecf20Sopenharmony_ci	__raw_writel(value, ptr);
1608c2ecf20Sopenharmony_ci	(void)__raw_readl(ptr);	/* Defeat write posting */
1618c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1628c2ecf20Sopenharmony_ci	return 0;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic unsigned long intc_mode_field(unsigned long addr,
1668c2ecf20Sopenharmony_ci				     unsigned long handle,
1678c2ecf20Sopenharmony_ci				     unsigned long (*fn)(unsigned long,
1688c2ecf20Sopenharmony_ci						unsigned long,
1698c2ecf20Sopenharmony_ci						unsigned long),
1708c2ecf20Sopenharmony_ci				     unsigned int irq)
1718c2ecf20Sopenharmony_ci{
1728c2ecf20Sopenharmony_ci	return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_cistatic unsigned long intc_mode_zero(unsigned long addr,
1768c2ecf20Sopenharmony_ci				    unsigned long handle,
1778c2ecf20Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
1788c2ecf20Sopenharmony_ci					       unsigned long,
1798c2ecf20Sopenharmony_ci					       unsigned long),
1808c2ecf20Sopenharmony_ci				    unsigned int irq)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	return fn(addr, handle, 0);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic unsigned long intc_mode_prio(unsigned long addr,
1868c2ecf20Sopenharmony_ci				    unsigned long handle,
1878c2ecf20Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
1888c2ecf20Sopenharmony_ci					       unsigned long,
1898c2ecf20Sopenharmony_ci					       unsigned long),
1908c2ecf20Sopenharmony_ci				    unsigned int irq)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	return fn(addr, handle, intc_get_prio_level(irq));
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ciunsigned long (*intc_reg_fns[])(unsigned long addr,
1968c2ecf20Sopenharmony_ci				unsigned long h,
1978c2ecf20Sopenharmony_ci				unsigned long data) = {
1988c2ecf20Sopenharmony_ci	[REG_FN_TEST_BASE + 0] = test_8,
1998c2ecf20Sopenharmony_ci	[REG_FN_TEST_BASE + 1] = test_16,
2008c2ecf20Sopenharmony_ci	[REG_FN_TEST_BASE + 3] = test_32,
2018c2ecf20Sopenharmony_ci	[REG_FN_WRITE_BASE + 0] = write_8,
2028c2ecf20Sopenharmony_ci	[REG_FN_WRITE_BASE + 1] = write_16,
2038c2ecf20Sopenharmony_ci	[REG_FN_WRITE_BASE + 3] = write_32,
2048c2ecf20Sopenharmony_ci	[REG_FN_MODIFY_BASE + 0] = modify_8,
2058c2ecf20Sopenharmony_ci	[REG_FN_MODIFY_BASE + 1] = modify_16,
2068c2ecf20Sopenharmony_ci	[REG_FN_MODIFY_BASE + 3] = modify_32,
2078c2ecf20Sopenharmony_ci};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ciunsigned long (*intc_enable_fns[])(unsigned long addr,
2108c2ecf20Sopenharmony_ci				   unsigned long handle,
2118c2ecf20Sopenharmony_ci				   unsigned long (*fn)(unsigned long,
2128c2ecf20Sopenharmony_ci					    unsigned long,
2138c2ecf20Sopenharmony_ci					    unsigned long),
2148c2ecf20Sopenharmony_ci				   unsigned int irq) = {
2158c2ecf20Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_field,
2168c2ecf20Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_zero,
2178c2ecf20Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
2188c2ecf20Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_prio,
2198c2ecf20Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_prio,
2208c2ecf20Sopenharmony_ci};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ciunsigned long (*intc_disable_fns[])(unsigned long addr,
2238c2ecf20Sopenharmony_ci				    unsigned long handle,
2248c2ecf20Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
2258c2ecf20Sopenharmony_ci					     unsigned long,
2268c2ecf20Sopenharmony_ci					     unsigned long),
2278c2ecf20Sopenharmony_ci				    unsigned int irq) = {
2288c2ecf20Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_zero,
2298c2ecf20Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_field,
2308c2ecf20Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
2318c2ecf20Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_zero,
2328c2ecf20Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_field,
2338c2ecf20Sopenharmony_ci};
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ciunsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
2368c2ecf20Sopenharmony_ci					  unsigned long handle,
2378c2ecf20Sopenharmony_ci					  unsigned long (*fn)(unsigned long,
2388c2ecf20Sopenharmony_ci						unsigned long,
2398c2ecf20Sopenharmony_ci						unsigned long),
2408c2ecf20Sopenharmony_ci					  unsigned int irq) = {
2418c2ecf20Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_field,
2428c2ecf20Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_zero,
2438c2ecf20Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
2448c2ecf20Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_field,
2458c2ecf20Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_field,
2468c2ecf20Sopenharmony_ci};
247