File Index
Files and directories
Sign in
FILE

integrator_ap.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm/mach-versatile/integrator_ap.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
  4 */
  5#include <linux/kernel.h>
  6#include <linux/init.h>
  7#include <linux/syscore_ops.h>
  8#include <linux/amba/bus.h>
  9#include <linux/io.h>
 10#include <linux/irqchip.h>
 11#include <linux/of_irq.h>
 12#include <linux/of_address.h>
 13#include <linux/of_platform.h>
 14#include <linux/uaccess.h>
 15#include <linux/termios.h>
 16#include <linux/mfd/syscon.h>
 17#include <linux/regmap.h>
 18
 19#include <asm/mach/arch.h>
 20#include <asm/mach/map.h>
 21
 22#include "integrator-hardware.h"
 23#include "integrator-cm.h"
 24#include "integrator.h"
 25
 26/* Regmap to the AP system controller */
 27static struct regmap *ap_syscon_map;
 28
 29/*
 30 * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
 31 * is the (PA >> 12).
 32 *
 33 * Setup a VA for the Integrator interrupt controller (for header #0,
 34 * just for now).
 35 */
 36#define VA_IC_BASE	__io_address(INTEGRATOR_IC_BASE)
 37
 38/*
 39 * Logical      Physical
 40 * f1400000	14000000	Interrupt controller
 41 * f1600000	16000000	UART 0
 42 */
 43
 44static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
 45	{
 46		.virtual	= IO_ADDRESS(INTEGRATOR_IC_BASE),
 47		.pfn		= __phys_to_pfn(INTEGRATOR_IC_BASE),
 48		.length		= SZ_4K,
 49		.type		= MT_DEVICE
 50	}, {
 51		.virtual	= IO_ADDRESS(INTEGRATOR_UART0_BASE),
 52		.pfn		= __phys_to_pfn(INTEGRATOR_UART0_BASE),
 53		.length		= SZ_4K,
 54		.type		= MT_DEVICE
 55	}
 56};
 57
 58static void __init ap_map_io(void)
 59{
 60	iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
 61}
 62
 63#ifdef CONFIG_PM
 64static unsigned long ic_irq_enable;
 65
 66static int irq_suspend(void *data)
 67{
 68	ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
 69	return 0;
 70}
 71
 72static void irq_resume(void *data)
 73{
 74	/* disable all irq sources */
 75	cm_clear_irqs();
 76	writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
 77	writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
 78
 79	writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
 80}
 81#else
 82#define irq_suspend NULL
 83#define irq_resume NULL
 84#endif
 85
 86static const struct syscore_ops irq_syscore_ops = {
 87	.suspend	= irq_suspend,
 88	.resume		= irq_resume,
 89};
 90
 91static struct syscore irq_syscore = {
 92	.ops = &irq_syscore_ops,
 93};
 94
 95static int __init irq_syscore_init(void)
 96{
 97	register_syscore(&irq_syscore);
 98
 99	return 0;
100}
101
102device_initcall(irq_syscore_init);
103
104/*
105 * For the PL010 found in the Integrator/AP some of the UART control is
106 * implemented in the system controller and accessed using a callback
107 * from the driver.
108 */
109static void integrator_uart_set_mctrl(struct amba_device *dev,
110				void __iomem *base, unsigned int mctrl)
111{
112	unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
113	u32 phybase = dev->res.start;
114	int ret;
115
116	if (phybase == INTEGRATOR_UART0_BASE) {
117		/* UART0 */
118		rts_mask = 1 << 4;
119		dtr_mask = 1 << 5;
120	} else {
121		/* UART1 */
122		rts_mask = 1 << 6;
123		dtr_mask = 1 << 7;
124	}
125
126	if (mctrl & TIOCM_RTS)
127		ctrlc |= rts_mask;
128	else
129		ctrls |= rts_mask;
130
131	if (mctrl & TIOCM_DTR)
132		ctrlc |= dtr_mask;
133	else
134		ctrls |= dtr_mask;
135
136	ret = regmap_write(ap_syscon_map,
137			   INTEGRATOR_SC_CTRLS_OFFSET,
138			   ctrls);
139	if (ret)
140		pr_err("MODEM: unable to write PL010 UART CTRLS\n");
141
142	ret = regmap_write(ap_syscon_map,
143			   INTEGRATOR_SC_CTRLC_OFFSET,
144			   ctrlc);
145	if (ret)
146		pr_err("MODEM: unable to write PL010 UART CRTLC\n");
147}
148
149struct amba_pl010_data ap_uart_data = {
150	.set_mctrl = integrator_uart_set_mctrl,
151};
152
153static void __init ap_init_irq_of(void)
154{
155	cm_init();
156	irqchip_init();
157}
158
159/* For the Device Tree, add in the UART callbacks as AUXDATA */
160static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = {
161	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
162		"uart0", &ap_uart_data),
163	OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
164		"uart1", &ap_uart_data),
165	{ /* sentinel */ },
166};
167
168static const struct of_device_id ap_syscon_match[] = {
169	{ .compatible = "arm,integrator-ap-syscon"},
170	{ },
171};
172
173static void __init ap_init_of(void)
174{
175	struct device_node *syscon;
176
177	of_platform_default_populate(NULL, ap_auxdata_lookup, NULL);
178
179	syscon = of_find_matching_node(NULL, ap_syscon_match);
180	if (!syscon)
181		return;
182	ap_syscon_map = syscon_node_to_regmap(syscon);
183	if (IS_ERR(ap_syscon_map)) {
184		pr_crit("could not find Integrator/AP system controller\n");
185		return;
186	}
187}
188
189static const char * ap_dt_board_compat[] = {
190	"arm,integrator-ap",
191	NULL,
192};
193
194DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
195	.reserve	= integrator_reserve,
196	.map_io		= ap_map_io,
197	.init_irq	= ap_init_irq_of,
198	.init_machine	= ap_init_of,
199	.dt_compat      = ap_dt_board_compat,
200MACHINE_END
~/ Read-only file preview.