sh: Preliminary support for the SH-X3 CPU.
This adds basic support for UP SH-X3. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
This commit is contained in:
@@ -340,8 +340,27 @@ ENTRY(vbr_base)
|
||||
general_exception:
|
||||
mov.l 1f, k2
|
||||
mov.l 2f, k3
|
||||
#ifdef CONFIG_CPU_SUBTYPE_SHX3
|
||||
mov.l @k2, k2
|
||||
|
||||
! Is EXPEVT larger than 0x800?
|
||||
mov #0x8, k0
|
||||
shll8 k0
|
||||
cmp/hs k0, k2
|
||||
bf 0f
|
||||
|
||||
! then add 0x580 (k2 is 0xd80 or 0xda0)
|
||||
mov #0x58, k0
|
||||
shll2 k0
|
||||
shll2 k0
|
||||
add k0, k2
|
||||
0:
|
||||
bra handle_exception
|
||||
nop
|
||||
#else
|
||||
bra handle_exception
|
||||
mov.l @k2, k2
|
||||
#endif
|
||||
.align 2
|
||||
1: .long EXPEVT
|
||||
2: .long ret_from_exception
|
||||
|
@@ -141,6 +141,14 @@ int __init detect_cpu_and_cache_system(void)
|
||||
current_cpu_data.flags |= CPU_HAS_LLSC;
|
||||
}
|
||||
break;
|
||||
case 0x4000: /* 1st cut */
|
||||
case 0x4001: /* 2nd cut */
|
||||
current_cpu_data.type = CPU_SHX3;
|
||||
current_cpu_data.icache.ways = 4;
|
||||
current_cpu_data.dcache.ways = 4;
|
||||
current_cpu_data.flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
|
||||
CPU_HAS_LLSC;
|
||||
break;
|
||||
case 0x8000:
|
||||
current_cpu_data.type = CPU_ST40RA;
|
||||
current_cpu_data.flags |= CPU_HAS_FPU;
|
||||
|
@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o
|
||||
obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o
|
||||
|
||||
# Primary on-chip clocks (common)
|
||||
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
|
||||
@@ -17,5 +18,6 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o
|
||||
clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o
|
||||
clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o
|
||||
clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o
|
||||
clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o
|
||||
|
||||
obj-y += $(clock-y)
|
||||
|
135
arch/sh/kernel/cpu/sh4a/clock-shx3.c
Normal file
135
arch/sh/kernel/cpu/sh4a/clock-shx3.c
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* arch/sh/kernel/cpu/sh4/clock-shx3.c
|
||||
*
|
||||
* SH-X3 support for the clock framework
|
||||
*
|
||||
* Copyright (C) 2006-2007 Renesas Technology Corp.
|
||||
* Copyright (C) 2006-2007 Renesas Solutions Corp.
|
||||
* Copyright (C) 2006-2007 Paul Mundt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/clock.h>
|
||||
#include <asm/freq.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
static int ifc_divisors[] = { 1, 2, 4 ,6 };
|
||||
static int bfc_divisors[] = { 1, 1, 1, 1, 1, 12, 16, 18, 24, 32, 36, 48 };
|
||||
static int pfc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 18, 24, 32, 36, 48 };
|
||||
static int cfc_divisors[] = { 1, 1, 4, 6 };
|
||||
|
||||
#define IFC_POS 28
|
||||
#define IFC_MSK 0x0003
|
||||
#define BFC_MSK 0x000f
|
||||
#define PFC_MSK 0x000f
|
||||
#define CFC_MSK 0x0003
|
||||
#define BFC_POS 16
|
||||
#define PFC_POS 0
|
||||
#define CFC_POS 20
|
||||
|
||||
static void master_clk_init(struct clk *clk)
|
||||
{
|
||||
clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK];
|
||||
}
|
||||
|
||||
static struct clk_ops shx3_master_clk_ops = {
|
||||
.init = master_clk_init,
|
||||
};
|
||||
|
||||
static void module_clk_recalc(struct clk *clk)
|
||||
{
|
||||
int idx = ((ctrl_inl(FRQCR) >> PFC_POS) & PFC_MSK);
|
||||
clk->rate = clk->parent->rate / pfc_divisors[idx];
|
||||
}
|
||||
|
||||
static struct clk_ops shx3_module_clk_ops = {
|
||||
.recalc = module_clk_recalc,
|
||||
};
|
||||
|
||||
static void bus_clk_recalc(struct clk *clk)
|
||||
{
|
||||
int idx = ((ctrl_inl(FRQCR) >> BFC_POS) & BFC_MSK);
|
||||
clk->rate = clk->parent->rate / bfc_divisors[idx];
|
||||
}
|
||||
|
||||
static struct clk_ops shx3_bus_clk_ops = {
|
||||
.recalc = bus_clk_recalc,
|
||||
};
|
||||
|
||||
static void cpu_clk_recalc(struct clk *clk)
|
||||
{
|
||||
int idx = ((ctrl_inl(FRQCR) >> IFC_POS) & IFC_MSK);
|
||||
clk->rate = clk->parent->rate / ifc_divisors[idx];
|
||||
}
|
||||
|
||||
static struct clk_ops shx3_cpu_clk_ops = {
|
||||
.recalc = cpu_clk_recalc,
|
||||
};
|
||||
|
||||
static struct clk_ops *shx3_clk_ops[] = {
|
||||
&shx3_master_clk_ops,
|
||||
&shx3_module_clk_ops,
|
||||
&shx3_bus_clk_ops,
|
||||
&shx3_cpu_clk_ops,
|
||||
};
|
||||
|
||||
void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
|
||||
{
|
||||
if (idx < ARRAY_SIZE(shx3_clk_ops))
|
||||
*ops = shx3_clk_ops[idx];
|
||||
}
|
||||
|
||||
static void shyway_clk_recalc(struct clk *clk)
|
||||
{
|
||||
int idx = ((ctrl_inl(FRQCR) >> CFC_POS) & CFC_MSK);
|
||||
clk->rate = clk->parent->rate / cfc_divisors[idx];
|
||||
}
|
||||
|
||||
static struct clk_ops shx3_shyway_clk_ops = {
|
||||
.recalc = shyway_clk_recalc,
|
||||
};
|
||||
|
||||
static struct clk shx3_shyway_clk = {
|
||||
.name = "shyway_clk",
|
||||
.flags = CLK_ALWAYS_ENABLED,
|
||||
.ops = &shx3_shyway_clk_ops,
|
||||
};
|
||||
|
||||
/*
|
||||
* Additional SHx3-specific on-chip clocks that aren't already part of the
|
||||
* clock framework
|
||||
*/
|
||||
static struct clk *shx3_onchip_clocks[] = {
|
||||
&shx3_shyway_clk,
|
||||
};
|
||||
|
||||
static int __init shx3_clk_init(void)
|
||||
{
|
||||
struct clk *clk = clk_get(NULL, "master_clk");
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(shx3_onchip_clocks); i++) {
|
||||
struct clk *clkp = shx3_onchip_clocks[i];
|
||||
|
||||
clkp->parent = clk;
|
||||
clk_register(clkp);
|
||||
clk_enable(clkp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now that we have the rest of the clocks registered, we need to
|
||||
* force the parent clock to propagate so that these clocks will
|
||||
* automatically figure out their rate. We cheat by handing the
|
||||
* parent clock its current rate and forcing child propagation.
|
||||
*/
|
||||
clk_set_rate(clk, clk_get_rate(clk));
|
||||
|
||||
clk_put(clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
arch_initcall(shx3_clk_init);
|
85
arch/sh/kernel/cpu/sh4a/setup-shx3.c
Normal file
85
arch/sh/kernel/cpu/sh4a/setup-shx3.c
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* SH-X3 Setup
|
||||
*
|
||||
* Copyright (C) 2007 Paul Mundt
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*/
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/io.h>
|
||||
#include <asm/sci.h>
|
||||
|
||||
static struct plat_sci_port sci_platform_data[] = {
|
||||
{
|
||||
.mapbase = 0xffc30000,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.type = PORT_SCIF,
|
||||
.irqs = { 40, 41, 43, 42 },
|
||||
}, {
|
||||
.mapbase = 0xffc40000,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.type = PORT_SCIF,
|
||||
.irqs = { 44, 45, 47, 46 },
|
||||
}, {
|
||||
.mapbase = 0xffc50000,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.type = PORT_SCIF,
|
||||
.irqs = { 48, 49, 51, 50 },
|
||||
}, {
|
||||
.mapbase = 0xffc60000,
|
||||
.flags = UPF_BOOT_AUTOCONF,
|
||||
.type = PORT_SCIF,
|
||||
.irqs = { 52, 53, 55, 54 },
|
||||
}, {
|
||||
.flags = 0,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device sci_device = {
|
||||
.name = "sh-sci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = sci_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device *shx3_devices[] __initdata = {
|
||||
&sci_device,
|
||||
};
|
||||
|
||||
static int __init shx3_devices_setup(void)
|
||||
{
|
||||
return platform_add_devices(shx3_devices,
|
||||
ARRAY_SIZE(shx3_devices));
|
||||
}
|
||||
__initcall(shx3_devices_setup);
|
||||
|
||||
static struct intc2_data intc2_irq_table[] = {
|
||||
{ 16, 0, 0, 0, 1, 2 }, /* TMU0 */
|
||||
{ 40, 4, 0, 0x20, 0, 3 }, /* SCIF0 ERI */
|
||||
{ 41, 4, 0, 0x20, 1, 3 }, /* SCIF0 RXI */
|
||||
{ 42, 4, 0, 0x20, 2, 3 }, /* SCIF0 BRI */
|
||||
{ 43, 4, 0, 0x20, 3, 3 }, /* SCIF0 TXI */
|
||||
};
|
||||
|
||||
static struct intc2_desc intc2_irq_desc __read_mostly = {
|
||||
.prio_base = 0xfe410000,
|
||||
.msk_base = 0xfe410820,
|
||||
.mskclr_base = 0xfe410850,
|
||||
|
||||
.intc2_data = intc2_irq_table,
|
||||
.nr_irqs = ARRAY_SIZE(intc2_irq_table),
|
||||
|
||||
.chip = {
|
||||
.name = "INTC2-SHX3",
|
||||
},
|
||||
};
|
||||
|
||||
void __init init_IRQ_intc2(void)
|
||||
{
|
||||
register_intc2_controller(&intc2_irq_desc);
|
||||
}
|
@@ -285,7 +285,7 @@ static const char *cpu_name[] = {
|
||||
[CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
|
||||
[CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
|
||||
[CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722",
|
||||
[CPU_SH_NONE] = "Unknown"
|
||||
[CPU_SHX3] = "SH-X3", [CPU_SH_NONE] = "Unknown"
|
||||
};
|
||||
|
||||
const char *get_cpu_subtype(struct sh_cpuinfo *c)
|
||||
|
@@ -30,7 +30,7 @@
|
||||
|
||||
static int tmu_timer_start(void)
|
||||
{
|
||||
ctrl_outb(ctrl_inb(TMU_TSTR) | 0x3, TMU_TSTR);
|
||||
ctrl_outb(ctrl_inb(TMU_012_TSTR) | 0x3, TMU_012_TSTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ static void tmu0_timer_set_interval(unsigned long interval, unsigned int reload)
|
||||
|
||||
static int tmu_timer_stop(void)
|
||||
{
|
||||
ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x3, TMU_TSTR);
|
||||
ctrl_outb(ctrl_inb(TMU_012_TSTR) & ~0x3, TMU_012_TSTR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,8 @@ static int tmu_timer_init(void)
|
||||
|
||||
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && \
|
||||
!defined(CONFIG_CPU_SUBTYPE_SH7760) && \
|
||||
!defined(CONFIG_CPU_SUBTYPE_SH7785)
|
||||
!defined(CONFIG_CPU_SUBTYPE_SH7785) && \
|
||||
!defined(CONFIG_CPU_SUBTYPE_SHX3)
|
||||
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user