xref: /kernel/linux/linux-6.6/drivers/sh/intc/access.c (revision 62306a36)
162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Common INTC2 register accessors
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (C) 2007, 2008 Magnus Damm
562306a36Sopenharmony_ci * Copyright (C) 2009, 2010 Paul Mundt
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
862306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
962306a36Sopenharmony_ci * for more details.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include "internals.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ciunsigned long intc_phys_to_virt(struct intc_desc_int *d, unsigned long address)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	struct intc_window *window;
1762306a36Sopenharmony_ci	int k;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	/* scan through physical windows and convert address */
2062306a36Sopenharmony_ci	for (k = 0; k < d->nr_windows; k++) {
2162306a36Sopenharmony_ci		window = d->window + k;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci		if (address < window->phys)
2462306a36Sopenharmony_ci			continue;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci		if (address >= (window->phys + window->size))
2762306a36Sopenharmony_ci			continue;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci		address -= window->phys;
3062306a36Sopenharmony_ci		address += (unsigned long)window->virt;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci		return address;
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci	/* no windows defined, register must be 1:1 mapped virt:phys */
3662306a36Sopenharmony_ci	return address;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ciunsigned int intc_get_reg(struct intc_desc_int *d, unsigned long address)
4062306a36Sopenharmony_ci{
4162306a36Sopenharmony_ci	unsigned int k;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	address = intc_phys_to_virt(d, address);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	for (k = 0; k < d->nr_reg; k++) {
4662306a36Sopenharmony_ci		if (d->reg[k] == address)
4762306a36Sopenharmony_ci			return k;
4862306a36Sopenharmony_ci	}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	BUG();
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ciunsigned int intc_set_field_from_handle(unsigned int value,
5562306a36Sopenharmony_ci					unsigned int field_value,
5662306a36Sopenharmony_ci					unsigned int handle)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	unsigned int width = _INTC_WIDTH(handle);
5962306a36Sopenharmony_ci	unsigned int shift = _INTC_SHIFT(handle);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	value &= ~(((1 << width) - 1) << shift);
6262306a36Sopenharmony_ci	value |= field_value << shift;
6362306a36Sopenharmony_ci	return value;
6462306a36Sopenharmony_ci}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ciunsigned long intc_get_field_from_handle(unsigned int value, unsigned int handle)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	unsigned int width = _INTC_WIDTH(handle);
6962306a36Sopenharmony_ci	unsigned int shift = _INTC_SHIFT(handle);
7062306a36Sopenharmony_ci	unsigned int mask = ((1 << width) - 1) << shift;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return (value & mask) >> shift;
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic unsigned long test_8(unsigned long addr, unsigned long h,
7662306a36Sopenharmony_ci			    unsigned long ignore)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
7962306a36Sopenharmony_ci	return intc_get_field_from_handle(__raw_readb(ptr), h);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistatic unsigned long test_16(unsigned long addr, unsigned long h,
8362306a36Sopenharmony_ci			     unsigned long ignore)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
8662306a36Sopenharmony_ci	return intc_get_field_from_handle(__raw_readw(ptr), h);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic unsigned long test_32(unsigned long addr, unsigned long h,
9062306a36Sopenharmony_ci			     unsigned long ignore)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
9362306a36Sopenharmony_ci	return intc_get_field_from_handle(__raw_readl(ptr), h);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic unsigned long write_8(unsigned long addr, unsigned long h,
9762306a36Sopenharmony_ci			     unsigned long data)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
10062306a36Sopenharmony_ci	__raw_writeb(intc_set_field_from_handle(0, data, h), ptr);
10162306a36Sopenharmony_ci	(void)__raw_readb(ptr);	/* Defeat write posting */
10262306a36Sopenharmony_ci	return 0;
10362306a36Sopenharmony_ci}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic unsigned long write_16(unsigned long addr, unsigned long h,
10662306a36Sopenharmony_ci			      unsigned long data)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
10962306a36Sopenharmony_ci	__raw_writew(intc_set_field_from_handle(0, data, h), ptr);
11062306a36Sopenharmony_ci	(void)__raw_readw(ptr);	/* Defeat write posting */
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic unsigned long write_32(unsigned long addr, unsigned long h,
11562306a36Sopenharmony_ci			      unsigned long data)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
11862306a36Sopenharmony_ci	__raw_writel(intc_set_field_from_handle(0, data, h), ptr);
11962306a36Sopenharmony_ci	(void)__raw_readl(ptr);	/* Defeat write posting */
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic unsigned long modify_8(unsigned long addr, unsigned long h,
12462306a36Sopenharmony_ci			      unsigned long data)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
12762306a36Sopenharmony_ci	unsigned long flags;
12862306a36Sopenharmony_ci	unsigned int value;
12962306a36Sopenharmony_ci	local_irq_save(flags);
13062306a36Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readb(ptr), data, h);
13162306a36Sopenharmony_ci	__raw_writeb(value, ptr);
13262306a36Sopenharmony_ci	(void)__raw_readb(ptr);	/* Defeat write posting */
13362306a36Sopenharmony_ci	local_irq_restore(flags);
13462306a36Sopenharmony_ci	return 0;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic unsigned long modify_16(unsigned long addr, unsigned long h,
13862306a36Sopenharmony_ci			       unsigned long data)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
14162306a36Sopenharmony_ci	unsigned long flags;
14262306a36Sopenharmony_ci	unsigned int value;
14362306a36Sopenharmony_ci	local_irq_save(flags);
14462306a36Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readw(ptr), data, h);
14562306a36Sopenharmony_ci	__raw_writew(value, ptr);
14662306a36Sopenharmony_ci	(void)__raw_readw(ptr);	/* Defeat write posting */
14762306a36Sopenharmony_ci	local_irq_restore(flags);
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic unsigned long modify_32(unsigned long addr, unsigned long h,
15262306a36Sopenharmony_ci			       unsigned long data)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	void __iomem *ptr = (void __iomem *)addr;
15562306a36Sopenharmony_ci	unsigned long flags;
15662306a36Sopenharmony_ci	unsigned int value;
15762306a36Sopenharmony_ci	local_irq_save(flags);
15862306a36Sopenharmony_ci	value = intc_set_field_from_handle(__raw_readl(ptr), data, h);
15962306a36Sopenharmony_ci	__raw_writel(value, ptr);
16062306a36Sopenharmony_ci	(void)__raw_readl(ptr);	/* Defeat write posting */
16162306a36Sopenharmony_ci	local_irq_restore(flags);
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic unsigned long intc_mode_field(unsigned long addr,
16662306a36Sopenharmony_ci				     unsigned long handle,
16762306a36Sopenharmony_ci				     unsigned long (*fn)(unsigned long,
16862306a36Sopenharmony_ci						unsigned long,
16962306a36Sopenharmony_ci						unsigned long),
17062306a36Sopenharmony_ci				     unsigned int irq)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	return fn(addr, handle, ((1 << _INTC_WIDTH(handle)) - 1));
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic unsigned long intc_mode_zero(unsigned long addr,
17662306a36Sopenharmony_ci				    unsigned long handle,
17762306a36Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
17862306a36Sopenharmony_ci					       unsigned long,
17962306a36Sopenharmony_ci					       unsigned long),
18062306a36Sopenharmony_ci				    unsigned int irq)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return fn(addr, handle, 0);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic unsigned long intc_mode_prio(unsigned long addr,
18662306a36Sopenharmony_ci				    unsigned long handle,
18762306a36Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
18862306a36Sopenharmony_ci					       unsigned long,
18962306a36Sopenharmony_ci					       unsigned long),
19062306a36Sopenharmony_ci				    unsigned int irq)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	return fn(addr, handle, intc_get_prio_level(irq));
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ciunsigned long (*intc_reg_fns[])(unsigned long addr,
19662306a36Sopenharmony_ci				unsigned long h,
19762306a36Sopenharmony_ci				unsigned long data) = {
19862306a36Sopenharmony_ci	[REG_FN_TEST_BASE + 0] = test_8,
19962306a36Sopenharmony_ci	[REG_FN_TEST_BASE + 1] = test_16,
20062306a36Sopenharmony_ci	[REG_FN_TEST_BASE + 3] = test_32,
20162306a36Sopenharmony_ci	[REG_FN_WRITE_BASE + 0] = write_8,
20262306a36Sopenharmony_ci	[REG_FN_WRITE_BASE + 1] = write_16,
20362306a36Sopenharmony_ci	[REG_FN_WRITE_BASE + 3] = write_32,
20462306a36Sopenharmony_ci	[REG_FN_MODIFY_BASE + 0] = modify_8,
20562306a36Sopenharmony_ci	[REG_FN_MODIFY_BASE + 1] = modify_16,
20662306a36Sopenharmony_ci	[REG_FN_MODIFY_BASE + 3] = modify_32,
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ciunsigned long (*intc_enable_fns[])(unsigned long addr,
21062306a36Sopenharmony_ci				   unsigned long handle,
21162306a36Sopenharmony_ci				   unsigned long (*fn)(unsigned long,
21262306a36Sopenharmony_ci					    unsigned long,
21362306a36Sopenharmony_ci					    unsigned long),
21462306a36Sopenharmony_ci				   unsigned int irq) = {
21562306a36Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_field,
21662306a36Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_zero,
21762306a36Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
21862306a36Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_prio,
21962306a36Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_prio,
22062306a36Sopenharmony_ci};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ciunsigned long (*intc_disable_fns[])(unsigned long addr,
22362306a36Sopenharmony_ci				    unsigned long handle,
22462306a36Sopenharmony_ci				    unsigned long (*fn)(unsigned long,
22562306a36Sopenharmony_ci					     unsigned long,
22662306a36Sopenharmony_ci					     unsigned long),
22762306a36Sopenharmony_ci				    unsigned int irq) = {
22862306a36Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_zero,
22962306a36Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_field,
23062306a36Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
23162306a36Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_zero,
23262306a36Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_field,
23362306a36Sopenharmony_ci};
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ciunsigned long (*intc_enable_noprio_fns[])(unsigned long addr,
23662306a36Sopenharmony_ci					  unsigned long handle,
23762306a36Sopenharmony_ci					  unsigned long (*fn)(unsigned long,
23862306a36Sopenharmony_ci						unsigned long,
23962306a36Sopenharmony_ci						unsigned long),
24062306a36Sopenharmony_ci					  unsigned int irq) = {
24162306a36Sopenharmony_ci	[MODE_ENABLE_REG] = intc_mode_field,
24262306a36Sopenharmony_ci	[MODE_MASK_REG] = intc_mode_zero,
24362306a36Sopenharmony_ci	[MODE_DUAL_REG] = intc_mode_field,
24462306a36Sopenharmony_ci	[MODE_PRIO_REG] = intc_mode_field,
24562306a36Sopenharmony_ci	[MODE_PCLR_REG] = intc_mode_field,
24662306a36Sopenharmony_ci};
247