mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 10:01:43 +00:00
9b6d351a75
DT and DT-conversion-related changes for various ARM platforms. Most of these are to enable various devices on various boards, etc, and not necessarily worth enumerating. New boards and systems continue to come in as new devicetree files that don't require corresponding C changes any more, which is indicating that the system is starting to work fairly well. A few things worth pointing out: * ST Ericsson ux500 platforms have made the major push to move over to fully support the platform with DT. * Renesas platforms continue their conversion over from legacy platform devices to DT-based for hardware description. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJS4Vg8AAoJEIwa5zzehBx3tRkP/2dXiXerdB6V63HQ2UjA0J1w wnEqOrHXhIBPHVsAjRs+JOqG1iHxwQ+6qPtpxy//OZy5EN/hTamU5HBAKwcJvbbS He+a2xhOK6nsjr5QrEk2wupXOodhXDXoaU2mqJ51HAN9AOS68QVbHFh1jHs0f7S0 RaPVqHTlpXiiWMZ1ScVwl6qqM/hVcK6H3WOrHz09RWG2V/rFth4cJ6hkXBgqBeYU Zl24Z9mzStaTI7epDEZXq7jZTMX5lzArL2mCA0jKA+YdEy7KSh5GEzqDGu2qi230 wwmJ3g5X1WxDvedXPL0+gUffL7UcHWlEV1nl5KtwVsPf/vpsAUvwPLdlObUgA2nr /cVrdwQYLaPJKg6xq8IWxaS0K34kLdJyUwiNjKxw5s2GayWEwqGRWALn9TANdKz7 Wg+RT0UxjHPL8zj/N1uQV/fTdayHE6PnTPorESKDK0a6q9qqzdUypV3j13d9faIS FbASmq35zO2iOo4ji7SX6wP4ZwPWV1Yx9UBl4RNDlWu9MyB6jsjiJFT1nyr5PxGo WCf8U1Nv4tqCo01gE8AHR1qzlW7cOoya7VMTwDme6J5N9K3GpN+OXqCVItT1lfL2 s2I0OI6TiD7pTAM4WkgCZaKAhPaE/i2Vc9xlGdZ8L77J4allBtLXTAPpIAZj1Lfl a7NT9hbUIiEkTnO8BhHm =4o2d -----END PGP SIGNATURE----- Merge tag 'dt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc Pull ARM SoC DT updates from Olof Johansson: "DT and DT-conversion-related changes for various ARM platforms. Most of these are to enable various devices on various boards, etc, and not necessarily worth enumerating. New boards and systems continue to come in as new devicetree files that don't require corresponding C changes any more, which is indicating that the system is starting to work fairly well. A few things worth pointing out: * ST Ericsson ux500 platforms have made the major push to move over to fully support the platform with DT * Renesas platforms continue their conversion over from legacy platform devices to DT-based for hardware description" * tag 'dt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (327 commits) ARM: dts: SiRF: add pin group for USP0 with only RX or TX frame sync ARM: dts: SiRF: add lost usp1_uart_nostreamctrl pin group for atlas6 ARM: dts: sirf: add lost minigpsrtc device node ARM: dts: sirf: add clock, frequence-voltage table for CPU0 ARM: dts: sirf: add lost bus_width, clock and status for sdhci ARM: dts: sirf: add lost clocks for cphifbg ARM: dts: socfpga: add pl330 clock ARM: dts: socfpga: update L2 tag and data latency arm: sun7i: cubietruck: Enable the i2c controllers ARM: dts: add support for EXYNOS4412 based TINY4412 board ARM: dts: Add initial support for Arndale Octa board ARM: bcm2835: add USB controller to device tree ARM: dts: MSM8974: Add MMIO architected timer node ARM: dts: MSM8974: Add restart node ARM: dts: sun7i: external clock outputs ARM: dts: sun7i: Change 32768 Hz oscillator node name to clk@N style ARM: dts: sun7i: Add pin muxing options for clock outputs ARM: dts: sun7i: Add rtp controller node ARM: dts: sun5i: Add rtp controller node ARM: dts: sun4i: Add rtp controller node ...
572 lines
14 KiB
C
572 lines
14 KiB
C
/*
|
|
* linux/arch/arm/mach-integrator/integrator_ap.c
|
|
*
|
|
* Copyright (C) 2000-2003 Deep Blue Solutions Ltd
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/list.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/string.h>
|
|
#include <linux/syscore_ops.h>
|
|
#include <linux/amba/bus.h>
|
|
#include <linux/amba/kmi.h>
|
|
#include <linux/clocksource.h>
|
|
#include <linux/clockchips.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/io.h>
|
|
#include <linux/irqchip/versatile-fpga.h>
|
|
#include <linux/mtd/physmap.h>
|
|
#include <linux/clk.h>
|
|
#include <linux/platform_data/clk-integrator.h>
|
|
#include <linux/of_irq.h>
|
|
#include <linux/of_address.h>
|
|
#include <linux/of_platform.h>
|
|
#include <linux/stat.h>
|
|
#include <linux/sys_soc.h>
|
|
#include <linux/termios.h>
|
|
#include <linux/sched_clock.h>
|
|
|
|
#include <mach/hardware.h>
|
|
#include <mach/platform.h>
|
|
#include <asm/hardware/arm_timer.h>
|
|
#include <asm/setup.h>
|
|
#include <asm/param.h> /* HZ */
|
|
#include <asm/mach-types.h>
|
|
|
|
#include <mach/lm.h>
|
|
|
|
#include <asm/mach/arch.h>
|
|
#include <asm/mach/irq.h>
|
|
#include <asm/mach/map.h>
|
|
#include <asm/mach/time.h>
|
|
|
|
#include "cm.h"
|
|
#include "common.h"
|
|
#include "pci_v3.h"
|
|
|
|
/* Base address to the AP system controller */
|
|
void __iomem *ap_syscon_base;
|
|
/* Base address to the external bus interface */
|
|
static void __iomem *ebi_base;
|
|
|
|
|
|
/*
|
|
* All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx
|
|
* is the (PA >> 12).
|
|
*
|
|
* Setup a VA for the Integrator interrupt controller (for header #0,
|
|
* just for now).
|
|
*/
|
|
#define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE)
|
|
|
|
/*
|
|
* Logical Physical
|
|
* ef000000 Cache flush
|
|
* f1100000 11000000 System controller registers
|
|
* f1300000 13000000 Counter/Timer
|
|
* f1400000 14000000 Interrupt controller
|
|
* f1600000 16000000 UART 0
|
|
* f1700000 17000000 UART 1
|
|
* f1a00000 1a000000 Debug LEDs
|
|
* f1b00000 1b000000 GPIO
|
|
*/
|
|
|
|
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
|
|
{
|
|
.virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
|
|
.pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
|
|
.length = SZ_4K,
|
|
.type = MT_DEVICE
|
|
}, {
|
|
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
|
|
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
|
|
.length = SZ_4K,
|
|
.type = MT_DEVICE
|
|
}, {
|
|
.virtual = IO_ADDRESS(INTEGRATOR_UART0_BASE),
|
|
.pfn = __phys_to_pfn(INTEGRATOR_UART0_BASE),
|
|
.length = SZ_4K,
|
|
.type = MT_DEVICE
|
|
}, {
|
|
.virtual = IO_ADDRESS(INTEGRATOR_DBG_BASE),
|
|
.pfn = __phys_to_pfn(INTEGRATOR_DBG_BASE),
|
|
.length = SZ_4K,
|
|
.type = MT_DEVICE
|
|
}, {
|
|
.virtual = IO_ADDRESS(INTEGRATOR_AP_GPIO_BASE),
|
|
.pfn = __phys_to_pfn(INTEGRATOR_AP_GPIO_BASE),
|
|
.length = SZ_4K,
|
|
.type = MT_DEVICE
|
|
}
|
|
};
|
|
|
|
static void __init ap_map_io(void)
|
|
{
|
|
iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
|
|
pci_v3_early_init();
|
|
}
|
|
|
|
#ifdef CONFIG_PM
|
|
static unsigned long ic_irq_enable;
|
|
|
|
static int irq_suspend(void)
|
|
{
|
|
ic_irq_enable = readl(VA_IC_BASE + IRQ_ENABLE);
|
|
return 0;
|
|
}
|
|
|
|
static void irq_resume(void)
|
|
{
|
|
/* disable all irq sources */
|
|
cm_clear_irqs();
|
|
writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR);
|
|
writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR);
|
|
|
|
writel(ic_irq_enable, VA_IC_BASE + IRQ_ENABLE_SET);
|
|
}
|
|
#else
|
|
#define irq_suspend NULL
|
|
#define irq_resume NULL
|
|
#endif
|
|
|
|
static struct syscore_ops irq_syscore_ops = {
|
|
.suspend = irq_suspend,
|
|
.resume = irq_resume,
|
|
};
|
|
|
|
static int __init irq_syscore_init(void)
|
|
{
|
|
register_syscore_ops(&irq_syscore_ops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
device_initcall(irq_syscore_init);
|
|
|
|
/*
|
|
* Flash handling.
|
|
*/
|
|
static int ap_flash_init(struct platform_device *dev)
|
|
{
|
|
u32 tmp;
|
|
|
|
writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP,
|
|
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET);
|
|
|
|
tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) |
|
|
INTEGRATOR_EBI_WRITE_ENABLE;
|
|
writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
|
|
|
|
if (!(readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET)
|
|
& INTEGRATOR_EBI_WRITE_ENABLE)) {
|
|
writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
|
|
writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
|
|
writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void ap_flash_exit(struct platform_device *dev)
|
|
{
|
|
u32 tmp;
|
|
|
|
writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP,
|
|
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET);
|
|
|
|
tmp = readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) &
|
|
~INTEGRATOR_EBI_WRITE_ENABLE;
|
|
writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
|
|
|
|
if (readl(ebi_base + INTEGRATOR_EBI_CSR1_OFFSET) &
|
|
INTEGRATOR_EBI_WRITE_ENABLE) {
|
|
writel(0xa05f, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
|
|
writel(tmp, ebi_base + INTEGRATOR_EBI_CSR1_OFFSET);
|
|
writel(0, ebi_base + INTEGRATOR_EBI_LOCK_OFFSET);
|
|
}
|
|
}
|
|
|
|
static void ap_flash_set_vpp(struct platform_device *pdev, int on)
|
|
{
|
|
if (on)
|
|
writel(INTEGRATOR_SC_CTRL_nFLVPPEN,
|
|
ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET);
|
|
else
|
|
writel(INTEGRATOR_SC_CTRL_nFLVPPEN,
|
|
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET);
|
|
}
|
|
|
|
static struct physmap_flash_data ap_flash_data = {
|
|
.width = 4,
|
|
.init = ap_flash_init,
|
|
.exit = ap_flash_exit,
|
|
.set_vpp = ap_flash_set_vpp,
|
|
};
|
|
|
|
/*
|
|
* For the PL010 found in the Integrator/AP some of the UART control is
|
|
* implemented in the system controller and accessed using a callback
|
|
* from the driver.
|
|
*/
|
|
static void integrator_uart_set_mctrl(struct amba_device *dev,
|
|
void __iomem *base, unsigned int mctrl)
|
|
{
|
|
unsigned int ctrls = 0, ctrlc = 0, rts_mask, dtr_mask;
|
|
u32 phybase = dev->res.start;
|
|
|
|
if (phybase == INTEGRATOR_UART0_BASE) {
|
|
/* UART0 */
|
|
rts_mask = 1 << 4;
|
|
dtr_mask = 1 << 5;
|
|
} else {
|
|
/* UART1 */
|
|
rts_mask = 1 << 6;
|
|
dtr_mask = 1 << 7;
|
|
}
|
|
|
|
if (mctrl & TIOCM_RTS)
|
|
ctrlc |= rts_mask;
|
|
else
|
|
ctrls |= rts_mask;
|
|
|
|
if (mctrl & TIOCM_DTR)
|
|
ctrlc |= dtr_mask;
|
|
else
|
|
ctrls |= dtr_mask;
|
|
|
|
__raw_writel(ctrls, ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET);
|
|
__raw_writel(ctrlc, ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET);
|
|
}
|
|
|
|
struct amba_pl010_data ap_uart_data = {
|
|
.set_mctrl = integrator_uart_set_mctrl,
|
|
};
|
|
|
|
/*
|
|
* Where is the timer (VA)?
|
|
*/
|
|
#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
|
|
#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
|
|
#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
|
|
|
|
static unsigned long timer_reload;
|
|
|
|
static u64 notrace integrator_read_sched_clock(void)
|
|
{
|
|
return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
|
|
}
|
|
|
|
static void integrator_clocksource_init(unsigned long inrate,
|
|
void __iomem *base)
|
|
{
|
|
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
|
unsigned long rate = inrate;
|
|
|
|
if (rate >= 1500000) {
|
|
rate /= 16;
|
|
ctrl |= TIMER_CTRL_DIV16;
|
|
}
|
|
|
|
writel(0xffff, base + TIMER_LOAD);
|
|
writel(ctrl, base + TIMER_CTRL);
|
|
|
|
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
|
rate, 200, 16, clocksource_mmio_readl_down);
|
|
sched_clock_register(integrator_read_sched_clock, 16, rate);
|
|
}
|
|
|
|
static void __iomem * clkevt_base;
|
|
|
|
/*
|
|
* IRQ handler for the timer
|
|
*/
|
|
static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
|
|
{
|
|
struct clock_event_device *evt = dev_id;
|
|
|
|
/* clear the interrupt */
|
|
writel(1, clkevt_base + TIMER_INTCLR);
|
|
|
|
evt->event_handler(evt);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
|
|
{
|
|
u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
|
|
|
|
/* Disable timer */
|
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
|
switch (mode) {
|
|
case CLOCK_EVT_MODE_PERIODIC:
|
|
/* Enable the timer and start the periodic tick */
|
|
writel(timer_reload, clkevt_base + TIMER_LOAD);
|
|
ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
|
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
break;
|
|
case CLOCK_EVT_MODE_ONESHOT:
|
|
/* Leave the timer disabled, .set_next_event will enable it */
|
|
ctrl &= ~TIMER_CTRL_PERIODIC;
|
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
break;
|
|
case CLOCK_EVT_MODE_UNUSED:
|
|
case CLOCK_EVT_MODE_SHUTDOWN:
|
|
case CLOCK_EVT_MODE_RESUME:
|
|
default:
|
|
/* Just leave in disabled state */
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
|
|
{
|
|
unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
|
|
|
|
writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
|
writel(next, clkevt_base + TIMER_LOAD);
|
|
writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct clock_event_device integrator_clockevent = {
|
|
.name = "timer1",
|
|
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
|
|
.set_mode = clkevt_set_mode,
|
|
.set_next_event = clkevt_set_next_event,
|
|
.rating = 300,
|
|
};
|
|
|
|
static struct irqaction integrator_timer_irq = {
|
|
.name = "timer",
|
|
.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
|
|
.handler = integrator_timer_interrupt,
|
|
.dev_id = &integrator_clockevent,
|
|
};
|
|
|
|
static void integrator_clockevent_init(unsigned long inrate,
|
|
void __iomem *base, int irq)
|
|
{
|
|
unsigned long rate = inrate;
|
|
unsigned int ctrl = 0;
|
|
|
|
clkevt_base = base;
|
|
/* Calculate and program a divisor */
|
|
if (rate > 0x100000 * HZ) {
|
|
rate /= 256;
|
|
ctrl |= TIMER_CTRL_DIV256;
|
|
} else if (rate > 0x10000 * HZ) {
|
|
rate /= 16;
|
|
ctrl |= TIMER_CTRL_DIV16;
|
|
}
|
|
timer_reload = rate / HZ;
|
|
writel(ctrl, clkevt_base + TIMER_CTRL);
|
|
|
|
setup_irq(irq, &integrator_timer_irq);
|
|
clockevents_config_and_register(&integrator_clockevent,
|
|
rate,
|
|
1,
|
|
0xffffU);
|
|
}
|
|
|
|
void __init ap_init_early(void)
|
|
{
|
|
}
|
|
|
|
static void __init ap_of_timer_init(void)
|
|
{
|
|
struct device_node *node;
|
|
const char *path;
|
|
void __iomem *base;
|
|
int err;
|
|
int irq;
|
|
struct clk *clk;
|
|
unsigned long rate;
|
|
|
|
clk = clk_get_sys("ap_timer", NULL);
|
|
BUG_ON(IS_ERR(clk));
|
|
clk_prepare_enable(clk);
|
|
rate = clk_get_rate(clk);
|
|
|
|
err = of_property_read_string(of_aliases,
|
|
"arm,timer-primary", &path);
|
|
if (WARN_ON(err))
|
|
return;
|
|
node = of_find_node_by_path(path);
|
|
base = of_iomap(node, 0);
|
|
if (WARN_ON(!base))
|
|
return;
|
|
writel(0, base + TIMER_CTRL);
|
|
integrator_clocksource_init(rate, base);
|
|
|
|
err = of_property_read_string(of_aliases,
|
|
"arm,timer-secondary", &path);
|
|
if (WARN_ON(err))
|
|
return;
|
|
node = of_find_node_by_path(path);
|
|
base = of_iomap(node, 0);
|
|
if (WARN_ON(!base))
|
|
return;
|
|
irq = irq_of_parse_and_map(node, 0);
|
|
writel(0, base + TIMER_CTRL);
|
|
integrator_clockevent_init(rate, base, irq);
|
|
}
|
|
|
|
static const struct of_device_id fpga_irq_of_match[] __initconst = {
|
|
{ .compatible = "arm,versatile-fpga-irq", .data = fpga_irq_of_init, },
|
|
{ /* Sentinel */ }
|
|
};
|
|
|
|
static void __init ap_init_irq_of(void)
|
|
{
|
|
cm_init();
|
|
of_irq_init(fpga_irq_of_match);
|
|
integrator_clk_init(false);
|
|
}
|
|
|
|
/* For the Device Tree, add in the UART callbacks as AUXDATA */
|
|
static struct of_dev_auxdata ap_auxdata_lookup[] __initdata = {
|
|
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_RTC_BASE,
|
|
"rtc", NULL),
|
|
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART0_BASE,
|
|
"uart0", &ap_uart_data),
|
|
OF_DEV_AUXDATA("arm,primecell", INTEGRATOR_UART1_BASE,
|
|
"uart1", &ap_uart_data),
|
|
OF_DEV_AUXDATA("arm,primecell", KMI0_BASE,
|
|
"kmi0", NULL),
|
|
OF_DEV_AUXDATA("arm,primecell", KMI1_BASE,
|
|
"kmi1", NULL),
|
|
OF_DEV_AUXDATA("cfi-flash", INTEGRATOR_FLASH_BASE,
|
|
"physmap-flash", &ap_flash_data),
|
|
{ /* sentinel */ },
|
|
};
|
|
|
|
static const struct of_device_id ap_syscon_match[] = {
|
|
{ .compatible = "arm,integrator-ap-syscon"},
|
|
{ },
|
|
};
|
|
|
|
static const struct of_device_id ebi_match[] = {
|
|
{ .compatible = "arm,external-bus-interface"},
|
|
{ },
|
|
};
|
|
|
|
static void __init ap_init_of(void)
|
|
{
|
|
unsigned long sc_dec;
|
|
struct device_node *root;
|
|
struct device_node *syscon;
|
|
struct device_node *ebi;
|
|
struct device *parent;
|
|
struct soc_device *soc_dev;
|
|
struct soc_device_attribute *soc_dev_attr;
|
|
u32 ap_sc_id;
|
|
int err;
|
|
int i;
|
|
|
|
/* Here we create an SoC device for the root node */
|
|
root = of_find_node_by_path("/");
|
|
if (!root)
|
|
return;
|
|
|
|
syscon = of_find_matching_node(root, ap_syscon_match);
|
|
if (!syscon)
|
|
return;
|
|
ebi = of_find_matching_node(root, ebi_match);
|
|
if (!ebi)
|
|
return;
|
|
|
|
ap_syscon_base = of_iomap(syscon, 0);
|
|
if (!ap_syscon_base)
|
|
return;
|
|
ebi_base = of_iomap(ebi, 0);
|
|
if (!ebi_base)
|
|
return;
|
|
|
|
ap_sc_id = readl(ap_syscon_base);
|
|
|
|
soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
|
|
if (!soc_dev_attr)
|
|
return;
|
|
|
|
err = of_property_read_string(root, "compatible",
|
|
&soc_dev_attr->soc_id);
|
|
if (err)
|
|
return;
|
|
err = of_property_read_string(root, "model", &soc_dev_attr->machine);
|
|
if (err)
|
|
return;
|
|
soc_dev_attr->family = "Integrator";
|
|
soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
|
|
'A' + (ap_sc_id & 0x0f));
|
|
|
|
soc_dev = soc_device_register(soc_dev_attr);
|
|
if (IS_ERR(soc_dev)) {
|
|
kfree(soc_dev_attr->revision);
|
|
kfree(soc_dev_attr);
|
|
return;
|
|
}
|
|
|
|
parent = soc_device_to_device(soc_dev);
|
|
integrator_init_sysfs(parent, ap_sc_id);
|
|
|
|
of_platform_populate(root, of_default_bus_match_table,
|
|
ap_auxdata_lookup, parent);
|
|
|
|
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
|
|
for (i = 0; i < 4; i++) {
|
|
struct lm_device *lmdev;
|
|
|
|
if ((sc_dec & (16 << i)) == 0)
|
|
continue;
|
|
|
|
lmdev = kzalloc(sizeof(struct lm_device), GFP_KERNEL);
|
|
if (!lmdev)
|
|
continue;
|
|
|
|
lmdev->resource.start = 0xc0000000 + 0x10000000 * i;
|
|
lmdev->resource.end = lmdev->resource.start + 0x0fffffff;
|
|
lmdev->resource.flags = IORESOURCE_MEM;
|
|
lmdev->irq = irq_of_parse_and_map(syscon, i);
|
|
lmdev->id = i;
|
|
|
|
lm_device_register(lmdev);
|
|
}
|
|
}
|
|
|
|
static const char * ap_dt_board_compat[] = {
|
|
"arm,integrator-ap",
|
|
NULL,
|
|
};
|
|
|
|
DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
|
|
.reserve = integrator_reserve,
|
|
.map_io = ap_map_io,
|
|
.init_early = ap_init_early,
|
|
.init_irq = ap_init_irq_of,
|
|
.handle_irq = fpga_handle_irq,
|
|
.init_time = ap_of_timer_init,
|
|
.init_machine = ap_init_of,
|
|
.restart = integrator_restart,
|
|
.dt_compat = ap_dt_board_compat,
|
|
MACHINE_END
|