highbank.c 4.1 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
#include <asm/smp_scu.h>
30
#include <asm/smp_twd.h>
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/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 "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
	__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, },
	{}
};

88 89 90 91 92 93 94 95
#ifdef CONFIG_CACHE_L2X0
static void highbank_l2x0_disable(void)
{
	/* Disable PL310 L2 Cache controller */
	highbank_smc1(0x102, 0x0);
}
#endif

96 97 98
static void __init highbank_init_irq(void)
{
	of_irq_init(irq_match);
99 100 101 102

#ifdef CONFIG_CACHE_L2X0
	/* Enable PL310 L2 Cache controller */
	highbank_smc1(0x102, 0x1);
103
	l2x0_of_init(0, ~0UL);
104 105
	outer_cache.disable = highbank_l2x0_disable;
#endif
106 107
}

R
Rob Herring 已提交
108 109 110 111 112
static struct clk_lookup lookup = {
	.dev_id = "sp804",
	.con_id = NULL,
};

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
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();
R
Rob Herring 已提交
130 131
	lookup.clk = of_clk_get(np, 0);
	clkdev_add(&lookup);
132

133
	sp804_clocksource_and_sched_clock_init(timer_base + 0x20, "timer1");
134
	sp804_clockevents_init(timer_base, irq, "timer0");
135 136

	twd_local_timer_of_register();
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
}

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,
168
	.handle_irq	= gic_handle_irq,
169 170
	.init_machine	= highbank_init,
	.dt_compat	= highbank_match,
171
	.restart	= highbank_restart,
172
MACHINE_END