highbank.c 3.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
/*
 * Copyright 2010-2011 Calxeda, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
 */
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
25
#include <linux/smp.h>
26 27

#include <asm/cacheflush.h>
28
#include <asm/smp_plat.h>
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#include <asm/smp_scu.h>
#include <asm/hardware/arm_timer.h>
#include <asm/hardware/timer-sp.h>
#include <asm/hardware/gic.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
#include <mach/irqs.h>

#include "core.h"
#include "sysregs.h"

void __iomem *sregs_base;

#define HB_SCU_VIRT_BASE	0xfee00000
void __iomem *scu_base_addr = ((void __iomem *)(HB_SCU_VIRT_BASE));

static struct map_desc scu_io_desc __initdata = {
	.virtual	= HB_SCU_VIRT_BASE,
	.pfn		= 0, /* run-time */
	.length		= SZ_4K,
	.type		= MT_DEVICE,
};

static void __init highbank_scu_map_io(void)
{
	unsigned long base;

	/* Get SCU base */
	asm("mrc p15, 4, %0, c15, c0, 0" : "=r" (base));

	scu_io_desc.pfn = __phys_to_pfn(base);
	iotable_init(&scu_io_desc, 1);
}

static void __init highbank_map_io(void)
{
	highbank_scu_map_io();
	highbank_lluart_map_io();
}

#define HB_JUMP_TABLE_PHYS(cpu)		(0x40 + (0x10 * (cpu)))
#define HB_JUMP_TABLE_VIRT(cpu)		phys_to_virt(HB_JUMP_TABLE_PHYS(cpu))

void highbank_set_cpu_jump(int cpu, void *jump_addr)
{
76
	cpu = cpu_logical_map(cpu);
77
	writel(virt_to_phys(jump_addr), HB_JUMP_TABLE_VIRT(cpu));
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
	__cpuc_flush_dcache_area(HB_JUMP_TABLE_VIRT(cpu), 16);
	outer_clean_range(HB_JUMP_TABLE_PHYS(cpu),
			  HB_JUMP_TABLE_PHYS(cpu) + 15);
}

const static struct of_device_id irq_match[] = {
	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
	{}
};

static void __init highbank_init_irq(void)
{
	of_irq_init(irq_match);
	l2x0_of_init(0, ~0UL);
}

static void __init highbank_timer_init(void)
{
	int irq;
	struct device_node *np;
	void __iomem *timer_base;

	/* Map system registers */
	np = of_find_compatible_node(NULL, NULL, "calxeda,hb-sregs");
	sregs_base = of_iomap(np, 0);
	WARN_ON(!sregs_base);

	np = of_find_compatible_node(NULL, NULL, "arm,sp804");
	timer_base = of_iomap(np, 0);
	WARN_ON(!timer_base);
	irq = irq_of_parse_and_map(np, 0);

	highbank_clocks_init();

	sp804_clocksource_init(timer_base + 0x20, "timer1");
	sp804_clockevents_init(timer_base, irq, "timer0");
}

static struct sys_timer highbank_timer = {
	.init = highbank_timer_init,
};

static void highbank_power_off(void)
{
	hignbank_set_pwr_shutdown();
	scu_power_mode(scu_base_addr, SCU_PM_POWEROFF);

	while (1)
		cpu_do_idle();
}

static void __init highbank_init(void)
{
	pm_power_off = highbank_power_off;

	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}

static const char *highbank_match[] __initconst = {
	"calxeda,highbank",
	NULL,
};

DT_MACHINE_START(HIGHBANK, "Highbank")
	.map_io		= highbank_map_io,
	.init_irq	= highbank_init_irq,
	.timer		= &highbank_timer,
145
	.handle_irq	= gic_handle_irq,
146 147
	.init_machine	= highbank_init,
	.dt_compat	= highbank_match,
148
	.restart	= highbank_restart,
149
MACHINE_END