Commit 49fb2cd2 authored by Paul Mundt's avatar Paul Mundt

Merge branch 'master' into sh/st-integration

parents dfc34940 260af562
......@@ -16,7 +16,9 @@ config SUPERH
select HAVE_IOREMAP_PROT if MMU
select HAVE_ARCH_TRACEHOOK
select HAVE_DMA_API_DEBUG
select HAVE_DMA_ATTRS
select HAVE_PERF_EVENTS
select PERF_USE_VMALLOC
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_LZMA
......@@ -37,6 +39,7 @@ config SUPERH32
select HAVE_FTRACE_MCOUNT_RECORD
select HAVE_DYNAMIC_FTRACE
select HAVE_FUNCTION_TRACE_MCOUNT_TEST
select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_ARCH_KGDB
select ARCH_HIBERNATION_POSSIBLE if MMU
......@@ -170,6 +173,12 @@ config ARCH_HAS_CPU_IDLE_WAIT
config IO_TRAPPED
bool
config DMA_COHERENT
bool
config DMA_NONCOHERENT
def_bool !DMA_COHERENT
source "init/Kconfig"
source "kernel/Kconfig.freezer"
......@@ -220,6 +229,7 @@ config CPU_SHX2
config CPU_SHX3
bool
select DMA_COHERENT
config ARCH_SHMOBILE
bool
......@@ -761,17 +771,6 @@ config ENTRY_OFFSET
default "0x00010000" if PAGE_SIZE_64KB
default "0x00000000"
config UBC_WAKEUP
bool "Wakeup UBC on startup"
depends on CPU_SH4 && !CPU_SH4A
help
Selecting this option will wakeup the User Break Controller (UBC) on
startup. Although the UBC is left in an awake state when the processor
comes up, some boot loaders misbehave by putting the UBC to sleep in a
power saving state, which causes issues with things like ptrace().
If unsure, say N.
choice
prompt "Kernel command line"
optional
......@@ -818,7 +817,13 @@ config MAPLE
Dreamcast with a serial line terminal or a remote network
connection.
source "arch/sh/drivers/pci/Kconfig"
config PCI
bool "PCI support"
depends on SYS_SUPPORTS_PCI
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
your box. If you have PCI, say Y, otherwise N.
source "drivers/pci/pcie/Kconfig"
......
......@@ -136,6 +136,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += mach-systemh
machdir-$(CONFIG_SH_EDOSK7705) += mach-edosk7705
machdir-$(CONFIG_SH_HIGHLANDER) += mach-highlander
machdir-$(CONFIG_SH_MIGOR) += mach-migor
machdir-$(CONFIG_SH_AP325RXA) += mach-ap325rxa
machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09
machdir-$(CONFIG_SH_ECOVEC) += mach-ecovec24
machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780
......
#
# Specific board support, not covered by a mach group.
#
obj-$(CONFIG_SH_AP325RXA) += board-ap325rxa.o
obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o
obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o
obj-$(CONFIG_SH_URQUELL) += board-urquell.o
......
/*
* AP325RXA sdram self/auto-refresh setup code
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>
#include <asm/romimage-macros.h>
/* code to enter and leave self-refresh. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(ap325rxa_sdram_enter_start)
/* SBSC: disable power down and put in self-refresh mode */
mov.l 1f, r4
mov.l 2f, r1
mov.l @r4, r2
or r1, r2
mov.l 3f, r3
and r3, r2
mov.l r2, @r4
rts
nop
.balign 4
1: .long 0xfe400008 /* SDCR0 */
2: .long 0x00000400
3: .long 0xffff7fff
ENTRY(ap325rxa_sdram_enter_end)
.balign 4
ENTRY(ap325rxa_sdram_leave_start)
/* SBSC: set auto-refresh mode */
mov.l 1f, r4
mov.l @r4, r0
mov.l 4f, r1
and r1, r0
mov.l r0, @r4
mov.l 6f, r4
mov.l 8f, r0
mov.l @r4, r1
mov #-1, r4
add r4, r1
or r1, r0
mov.l 7f, r1
mov.l r0, @r1
rts
nop
.balign 4
1: .long 0xfe400008 /* SDCR0 */
4: .long 0xfffffbff
6: .long 0xfe40001c /* RTCOR */
7: .long 0xfe400018 /* RTCNT */
8: .long 0xa55a0000
ENTRY(ap325rxa_sdram_leave_end)
......@@ -20,8 +20,6 @@
#include <linux/i2c.h>
#include <linux/smsc911x.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_gpio.h>
#include <media/ov772x.h>
#include <media/soc_camera.h>
#include <media/soc_camera_platform.h>
......@@ -29,6 +27,7 @@
#include <video/sh_mobile_lcdc.h>
#include <asm/io.h>
#include <asm/clock.h>
#include <asm/suspend.h>
#include <cpu/sh7723.h>
static struct smsc911x_platform_config smsc911x_config = {
......@@ -409,17 +408,49 @@ static struct platform_device ceu_device = {
},
};
struct spi_gpio_platform_data sdcard_cn3_platform_data = {
.sck = GPIO_PTD0,
.mosi = GPIO_PTD1,
.miso = GPIO_PTD2,
.num_chipselect = 1,
static struct resource sdhi0_cn3_resources[] = {
[0] = {
.name = "SDHI0",
.start = 0x04ce0000,
.end = 0x04ce01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdcard_cn3_device = {
.name = "spi_gpio",
.dev = {
.platform_data = &sdcard_cn3_platform_data,
static struct platform_device sdhi0_cn3_device = {
.name = "sh_mobile_sdhi",
.id = 0, /* "sdhi0" clock */
.num_resources = ARRAY_SIZE(sdhi0_cn3_resources),
.resource = sdhi0_cn3_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI0,
},
};
static struct resource sdhi1_cn7_resources[] = {
[0] = {
.name = "SDHI1",
.start = 0x04cf0000,
.end = 0x04cf01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 24,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdhi1_cn7_device = {
.name = "sh_mobile_sdhi",
.id = 1, /* "sdhi1" clock */
.num_resources = ARRAY_SIZE(sdhi1_cn7_resources),
.resource = sdhi1_cn7_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI1,
},
};
......@@ -470,22 +501,26 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
&lcdc_device,
&ceu_device,
&nand_flash_device,
&sdcard_cn3_device,
&sdhi0_cn3_device,
&sdhi1_cn7_device,
&ap325rxa_camera[0],
&ap325rxa_camera[1],
};
static struct spi_board_info ap325rxa_spi_devices[] = {
{
.modalias = "mmc_spi",
.max_speed_hz = 5000000,
.chip_select = 0,
.controller_data = (void *) GPIO_PTD5,
},
};
extern char ap325rxa_sdram_enter_start;
extern char ap325rxa_sdram_enter_end;
extern char ap325rxa_sdram_leave_start;
extern char ap325rxa_sdram_leave_end;
static int __init ap325rxa_devices_setup(void)
{
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
&ap325rxa_sdram_enter_start,
&ap325rxa_sdram_enter_end,
&ap325rxa_sdram_leave_start,
&ap325rxa_sdram_leave_end);
/* LD3 and LD4 LEDs */
gpio_request(GPIO_PTX5, NULL); /* RUN */
gpio_direction_output(GPIO_PTX5, 1);
......@@ -578,12 +613,28 @@ static int __init ap325rxa_devices_setup(void)
platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20);
/* SDHI0 - CN3 - SD CARD */
gpio_request(GPIO_FN_SDHI0CD_PTD, NULL);
gpio_request(GPIO_FN_SDHI0WP_PTD, NULL);
gpio_request(GPIO_FN_SDHI0D3_PTD, NULL);
gpio_request(GPIO_FN_SDHI0D2_PTD, NULL);
gpio_request(GPIO_FN_SDHI0D1_PTD, NULL);
gpio_request(GPIO_FN_SDHI0D0_PTD, NULL);
gpio_request(GPIO_FN_SDHI0CMD_PTD, NULL);
gpio_request(GPIO_FN_SDHI0CLK_PTD, NULL);
/* SDHI1 - CN7 - MICRO SD CARD */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1D3, NULL);
gpio_request(GPIO_FN_SDHI1D2, NULL);
gpio_request(GPIO_FN_SDHI1D1, NULL);
gpio_request(GPIO_FN_SDHI1D0, NULL);
gpio_request(GPIO_FN_SDHI1CMD, NULL);
gpio_request(GPIO_FN_SDHI1CLK, NULL);
i2c_register_board_info(0, ap325rxa_i2c_devices,
ARRAY_SIZE(ap325rxa_i2c_devices));
spi_register_board_info(ap325rxa_spi_devices,
ARRAY_SIZE(ap325rxa_spi_devices));
return platform_add_devices(ap325rxa_devices,
ARRAY_SIZE(ap325rxa_devices));
}
......
......@@ -6,4 +6,4 @@
# for more details.
#
obj-y := setup.o
\ No newline at end of file
obj-y := setup.o sdram.o
\ No newline at end of file
/*
* Ecovec24 sdram self/auto-refresh setup code
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>
#include <asm/romimage-macros.h>
/* code to enter and leave self-refresh. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(ecovec24_sdram_enter_start)
/* DBSC: put memory in self-refresh mode */
ED 0xFD000010, 0x00000000 /* DBEN */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
rts
nop
ENTRY(ecovec24_sdram_enter_end)
.balign 4
ENTRY(ecovec24_sdram_leave_start)
/* DBSC: put memory in auto-refresh mode */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
WAIT 1
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000010, 0x00000001 /* DBEN */
ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
rts
nop
ENTRY(ecovec24_sdram_leave_end)
......@@ -26,6 +26,7 @@
#include <asm/sh_eth.h>
#include <asm/sh_keysc.h>
#include <asm/clock.h>
#include <asm/suspend.h>
#include <cpu/sh7724.h>
/*
......@@ -147,6 +148,9 @@ static struct platform_device sh_eth_device = {
},
.num_resources = ARRAY_SIZE(sh_eth_resources),
.resource = sh_eth_resources,
.archdata = {
.hwblk_id = HWBLK_ETHER,
},
};
/* USB0 host */
......@@ -185,30 +189,18 @@ static struct platform_device usb0_host_device = {
.resource = usb0_host_resources,
};
/*
* USB1
*
* CN5 can use both host/function,
* and we can determine it by checking PTB[3]
*
* This time only USB1 host is supported.
*/
/* USB1 host/function */
void usb1_port_power(int port, int power)
{
if (!gpio_get_value(GPIO_PTB3)) {
printk(KERN_ERR "USB1 function is not supported\n");
return;
}
gpio_set_value(GPIO_PTB5, power);
}
static struct r8a66597_platdata usb1_host_data = {
static struct r8a66597_platdata usb1_common_data = {
.on_chip = 1,
.port_power = usb1_port_power,
};
static struct resource usb1_host_resources[] = {
static struct resource usb1_common_resources[] = {
[0] = {
.start = 0xa4d90000,
.end = 0xa4d90124 - 1,
......@@ -221,16 +213,16 @@ static struct resource usb1_host_resources[] = {
},
};
static struct platform_device usb1_host_device = {
.name = "r8a66597_hcd",
static struct platform_device usb1_common_device = {
/* .name will be added in arch_setup */
.id = 1,
.dev = {
.dma_mask = NULL, /* not use dma */
.coherent_dma_mask = 0xffffffff,
.platform_data = &usb1_host_data,
.platform_data = &usb1_common_data,
},
.num_resources = ARRAY_SIZE(usb1_host_resources),
.resource = usb1_host_resources,
.num_resources = ARRAY_SIZE(usb1_common_resources),
.resource = usb1_common_resources,
};
/* LCDC */
......@@ -428,16 +420,66 @@ static struct i2c_board_info ts_i2c_clients = {
.irq = IRQ0,
};
/* SHDI0 */
static struct resource sdhi0_resources[] = {
[0] = {
.name = "SDHI0",
.start = 0x04ce0000,
.end = 0x04ce01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdhi0_device = {
.name = "sh_mobile_sdhi",
.num_resources = ARRAY_SIZE(sdhi0_resources),
.resource = sdhi0_resources,
.id = 0,
.archdata = {
.hwblk_id = HWBLK_SDHI0,
},
};
/* SHDI1 */
static struct resource sdhi1_resources[] = {
[0] = {
.name = "SDHI1",
.start = 0x04cf0000,
.end = 0x04cf01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 24,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdhi1_device = {
.name = "sh_mobile_sdhi",
.num_resources = ARRAY_SIZE(sdhi1_resources),
.resource = sdhi1_resources,
.id = 1,
.archdata = {
.hwblk_id = HWBLK_SDHI1,
},
};
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
&sh_eth_device,
&usb0_host_device,
&usb1_host_device, /* USB1 host support */
&usb1_common_device,
&lcdc_device,
&ceu0_device,
&ceu1_device,
&keysc_device,
&sdhi0_device,
&sdhi1_device,
};
#define EEPROM_ADDR 0x50
......@@ -466,12 +508,9 @@ static u8 mac_read(struct i2c_adapter *a, u8 command)
return buf;
}
#define MAC_LEN 6
static void __init sh_eth_init(void)
static void __init sh_eth_init(struct sh_eth_plat_data *pd)
{
struct i2c_adapter *a = i2c_get_adapter(1);
struct clk *eth_clk;
u8 mac[MAC_LEN];
int i;
if (!a) {
......@@ -479,39 +518,30 @@ static void __init sh_eth_init(void)
return;
}
eth_clk = clk_get(NULL, "eth0");
if (!eth_clk) {
pr_err("can not get eth0 clk\n");
return;
}
/* read MAC address frome EEPROM */
for (i = 0; i < MAC_LEN; i++) {
mac[i] = mac_read(a, 0x10 + i);
for (i = 0; i < sizeof(pd->mac_addr); i++) {
pd->mac_addr[i] = mac_read(a, 0x10 + i);
msleep(10);
}
/* clock enable */
clk_enable(eth_clk);
/* reset sh-eth */
ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
/* set MAC addr */
ctrl_outl((mac[0] << 24) |
(mac[1] << 16) |
(mac[2] << 8) |
(mac[3] << 0), SH_ETH_MAHR);
ctrl_outl((mac[4] << 8) |
(mac[5] << 0), SH_ETH_MALR);
clk_put(eth_clk);
}
#define PORT_HIZA 0xA4050158
#define IODRIVEA 0xA405018A
extern char ecovec24_sdram_enter_start;
extern char ecovec24_sdram_enter_end;
extern char ecovec24_sdram_leave_start;
extern char ecovec24_sdram_leave_end;
static int __init arch_setup(void)
{
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
&ecovec24_sdram_enter_start,
&ecovec24_sdram_enter_end,
&ecovec24_sdram_leave_start,
&ecovec24_sdram_leave_end);
/* enable STATUS0, STATUS2 and PDSTATUS */
gpio_request(GPIO_FN_STATUS0, NULL);
gpio_request(GPIO_FN_STATUS2, NULL);
......@@ -561,6 +591,14 @@ static int __init arch_setup(void)
ctrl_outw(0x0600, 0xa40501d4);
ctrl_outw(0x0600, 0xa4050192);
if (gpio_get_value(GPIO_PTB3)) {
printk(KERN_INFO "USB1 function is selected\n");
usb1_common_device.name = "r8a66597_udc";
} else {
printk(KERN_INFO "USB1 host is selected\n");
usb1_common_device.name = "r8a66597_hcd";
}
/* enable LCDC */
gpio_request(GPIO_FN_LCDD23, NULL);
gpio_request(GPIO_FN_LCDD22, NULL);
......@@ -710,6 +748,34 @@ static int __init arch_setup(void)
gpio_direction_input(GPIO_PTR5);
gpio_direction_input(GPIO_PTR6);
/* enable SDHI0 */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL);
gpio_request(GPIO_FN_SDHI0CMD, NULL);
gpio_request(GPIO_FN_SDHI0CLK, NULL);
gpio_request(GPIO_FN_SDHI0D3, NULL);
gpio_request(GPIO_FN_SDHI0D2, NULL);
gpio_request(GPIO_FN_SDHI0D1, NULL);
gpio_request(GPIO_FN_SDHI0D0, NULL);
/* enable SDHI1 */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1WP, NULL);
gpio_request(GPIO_FN_SDHI1CMD, NULL);
gpio_request(GPIO_FN_SDHI1CLK, NULL);
gpio_request(GPIO_FN_SDHI1D3, NULL);
gpio_request(GPIO_FN_SDHI1D2, NULL);
gpio_request(GPIO_FN_SDHI1D1, NULL);
gpio_request(GPIO_FN_SDHI1D0, NULL);
gpio_request(GPIO_PTB6, NULL);
gpio_request(GPIO_PTB7, NULL);
gpio_direction_output(GPIO_PTB6, 1);
gpio_direction_output(GPIO_PTB7, 1);
/* I/O buffer drive ability is high for SDHI1 */
ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
/* enable I2C device */
i2c_register_board_info(1, i2c1_devices,
ARRAY_SIZE(i2c1_devices));
......@@ -721,12 +787,11 @@ arch_initcall(arch_setup);
static int __init devices_setup(void)
{
sh_eth_init();
sh_eth_init(&sh_eth_plat);
return 0;
}
device_initcall(devices_setup);
static struct sh_machine_vector mv_ecovec __initmv = {
.mv_name = "R0P7724 (EcoVec)",
};
......@@ -384,7 +384,7 @@ static unsigned char irl2irq[HL_NR_IRL];
static int highlander_irq_demux(int irq)
{
if (irq >= HL_NR_IRL || !irl2irq[irq])
if (irq >= HL_NR_IRL || irq < 0 || !irl2irq[irq])
return irq;
return irl2irq[irq];
......
obj-y := setup.o
obj-y := setup.o sdram.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += lcd_wqvga.o
/*
* KFR2R09 sdram self/auto-refresh setup code
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>
#include <asm/romimage-macros.h>
/* code to enter and leave self-refresh. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(kfr2r09_sdram_enter_start)
/* DBSC: put memory in self-refresh mode */
ED 0xFD000010, 0x00000000 /* DBEN */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
rts
nop
ENTRY(kfr2r09_sdram_enter_end)
.balign 4
ENTRY(kfr2r09_sdram_leave_start)
/* DBSC: put memory in auto-refresh mode */
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_RSTANDBY, r0
bf resume_rstandby
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
WAIT 1
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000010, 0x00000001 /* DBEN */
ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
rts
nop
resume_rstandby:
/* DBSC: re-initialize and put in auto-refresh */
ED 0xFD000108, 0x40000301 /* DBPDCNT0 */
ED 0xFD000020, 0x011B0002 /* DBCONF */
ED 0xFD000030, 0x03060E02 /* DBTR0 */
ED 0xFD000034, 0x01020102 /* DBTR1 */
ED 0xFD000038, 0x01090406 /* DBTR2 */
ED 0xFD000008, 0x00000004 /* DBKIND */
ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
ED 0xFD000018, 0x00000001 /* DBCKECNT */
WAIT 1
ED 0xFD000010, 0x00000001 /* DBEN */
ED 0xFD000044, 0x000004AF /* DBRFPDN1 */
ED 0xFD000048, 0x20CF0037 /* DBRFPDN2 */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000108, 0x40000300 /* DBPDCNT0 */
ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
rts
nop
ENTRY(kfr2r09_sdram_leave_end)
......@@ -18,7 +18,10 @@
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/usb/r8a66597.h>
#include <media/soc_camera.h>
#include <media/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/machvec.h>
#include <asm/io.h>
......@@ -212,11 +215,154 @@ static struct platform_device kfr2r09_usb0_gadget_device = {
.resource = kfr2r09_usb0_gadget_resources,
};
static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
.flags = SH_CEU_FLAG_USE_8BIT_BUS,
};
static struct resource kfr2r09_ceu_resources[] = {
[0] = {
.name = "CEU",
.start = 0xfe910000,
.end = 0xfe91009f,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 52,
.end = 52,
.flags = IORESOURCE_IRQ,
},
[2] = {
/* place holder for contiguous memory */
},
};
static struct platform_device kfr2r09_ceu_device = {
.name = "sh_mobile_ceu",
.id = 0, /* "ceu0" clock */
.num_resources = ARRAY_SIZE(kfr2r09_ceu_resources),
.resource = kfr2r09_ceu_resources,
.dev = {
.platform_data = &sh_mobile_ceu_info,
},
.archdata = {
.hwblk_id = HWBLK_CEU0,
},
};
static struct i2c_board_info kfr2r09_i2c_camera = {
I2C_BOARD_INFO("rj54n1cb0c", 0x50),
};
static struct clk *camera_clk;
#define DRVCRB 0xA405018C
static int camera_power(struct device *dev, int mode)
{
int ret;
if (mode) {
long rate;
camera_clk = clk_get(NULL, "video_clk");
if (IS_ERR(camera_clk))
return PTR_ERR(camera_clk);
/* set VIO_CKO clock to 25MHz */
rate = clk_round_rate(camera_clk, 25000000);
ret = clk_set_rate(camera_clk, rate);
if (ret < 0)
goto eclkrate;
/* set DRVCRB
*
* use 1.8 V for VccQ_VIO
* use 2.85V for VccQ_SR
*/
ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB);
/* reset clear */
ret = gpio_request(GPIO_PTB4, NULL);
if (ret < 0)
goto eptb4;
ret = gpio_request(GPIO_PTB7, NULL);
if (ret < 0)
goto eptb7;
ret = gpio_direction_output(GPIO_PTB4, 1);
if (!ret)
ret = gpio_direction_output(GPIO_PTB7, 1);
if (ret < 0)
goto egpioout;
msleep(1);
ret = clk_enable(camera_clk); /* start VIO_CKO */
if (ret < 0)
goto eclkon;
return 0;
}
ret = 0;
clk_disable(camera_clk);
eclkon:
gpio_set_value(GPIO_PTB7, 0);
egpioout:
gpio_set_value(GPIO_PTB4, 0);
gpio_free(GPIO_PTB7);
eptb7:
gpio_free(GPIO_PTB4);
eptb4:
eclkrate:
clk_put(camera_clk);
return ret;
}
static struct soc_camera_link rj54n1_link = {
.power = camera_power,
.board_info = &kfr2r09_i2c_camera,
.i2c_adapter_id = 1,
.module_name = "rj54n1cb0c",
};
static struct platform_device kfr2r09_camera = {
.name = "soc-camera-pdrv",
.id = 0,
.dev = {
.platform_data = &rj54n1_link,
},
};
static struct resource kfr2r09_sh_sdhi0_resources[] = {
[0] = {
.name = "SDHI0",
.start = 0x04ce0000,
.end = 0x04ce01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device kfr2r09_sh_sdhi0_device = {
.name = "sh_mobile_sdhi",
.num_resources = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources),
.resource = kfr2r09_sh_sdhi0_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI0,
},
};
static struct platform_device *kfr2r09_devices[] __initdata = {
&kfr2r09_nor_flash_device,
&kfr2r09_nand_flash_device,
&kfr2r09_sh_keysc_device,
&kfr2r09_sh_lcdc_device,
&kfr2r09_ceu_device,
&kfr2r09_camera,
&kfr2r09_sh_sdhi0_device,
};
#define BSC_CS0BCR 0xfec10004
......@@ -299,8 +445,21 @@ static int kfr2r09_usb0_gadget_setup(void)
return 0;
}
extern char kfr2r09_sdram_enter_start;
extern char kfr2r09_sdram_enter_end;
extern char kfr2r09_sdram_leave_start;
extern char kfr2r09_sdram_leave_end;
static int __init kfr2r09_devices_setup(void)
{
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF |
SUSP_SH_RSTANDBY,
&kfr2r09_sdram_enter_start,
&kfr2r09_sdram_enter_end,
&kfr2r09_sdram_leave_start,
&kfr2r09_sdram_leave_end);
/* enable SCIF1 serial port for YC401 console support */
gpio_request(GPIO_FN_SCIF1_RXD, NULL);
gpio_request(GPIO_FN_SCIF1_TXD, NULL);
......@@ -361,6 +520,32 @@ static int __init kfr2r09_devices_setup(void)
if (kfr2r09_usb0_gadget_setup() == 0)
platform_device_register(&kfr2r09_usb0_gadget_device);
/* CEU */
gpio_request(GPIO_FN_VIO_CKO, NULL);
gpio_request(GPIO_FN_VIO0_CLK, NULL);
gpio_request(GPIO_FN_VIO0_VD, NULL);
gpio_request(GPIO_FN_VIO0_HD, NULL);
gpio_request(GPIO_FN_VIO0_FLD, NULL);
gpio_request(GPIO_FN_VIO0_D7, NULL);
gpio_request(GPIO_FN_VIO0_D6, NULL);
gpio_request(GPIO_FN_VIO0_D5, NULL);
gpio_request(GPIO_FN_VIO0_D4, NULL);
gpio_request(GPIO_FN_VIO0_D3, NULL);
gpio_request(GPIO_FN_VIO0_D2, NULL);
gpio_request(GPIO_FN_VIO0_D1, NULL);
gpio_request(GPIO_FN_VIO0_D0, NULL);
platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20);
/* SDHI0 connected to yc304 */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0D3, NULL);
gpio_request(GPIO_FN_SDHI0D2, NULL);
gpio_request(GPIO_FN_SDHI0D1, NULL);
gpio_request(GPIO_FN_SDHI0D0, NULL);
gpio_request(GPIO_FN_SDHI0CMD, NULL);
gpio_request(GPIO_FN_SDHI0CLK, NULL);
return platform_add_devices(kfr2r09_devices,
ARRAY_SIZE(kfr2r09_devices));
}
......
obj-y := setup.o
obj-y := setup.o sdram.o
obj-$(CONFIG_SH_MIGOR_QVGA) += lcd_qvga.o
/*
* Migo-R sdram self/auto-refresh setup code
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>
#include <asm/romimage-macros.h>
/* code to enter and leave self-refresh. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(migor_sdram_enter_start)
/* SBSC: disable power down and put in self-refresh mode */
mov.l 1f, r4
mov.l 2f, r1
mov.l @r4, r2
or r1, r2
mov.l 3f, r3
and r3, r2
mov.l r2, @r4
rts
nop
.balign 4
1: .long 0xfe400008 /* SDCR0 */
2: .long 0x00000400
3: .long 0xffff7fff
ENTRY(migor_sdram_enter_end)
.balign 4
ENTRY(migor_sdram_leave_start)
/* SBSC: set auto-refresh mode */
mov.l 1f, r4
mov.l @r4, r0
mov.l 4f, r1
and r1, r0
mov.l r0, @r4
mov.l 6f, r4
mov.l 8f, r0
mov.l @r4, r1
mov #-1, r4
add r4, r1
or r1, r0
mov.l 7f, r1
mov.l r0, @r1
rts
nop
.balign 4
1: .long 0xfe400008 /* SDCR0 */
4: .long 0xfffffbff
6: .long 0xfe40001c /* RTCOR */
7: .long 0xfe400018 /* RTCNT */
8: .long 0xa55a0000
ENTRY(migor_sdram_leave_end)
......@@ -18,8 +18,6 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_gpio.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
#include <media/ov772x.h>
......@@ -28,6 +26,7 @@
#include <asm/machvec.h>
#include <asm/io.h>
#include <asm/sh_keysc.h>
#include <asm/suspend.h>
#include <mach/migor.h>
#include <cpu/sh7722.h>
......@@ -390,17 +389,25 @@ static struct platform_device migor_ceu_device = {
},
};
struct spi_gpio_platform_data sdcard_cn9_platform_data = {
.sck = GPIO_PTD0,
.mosi = GPIO_PTD1,
.miso = GPIO_PTD2,
.num_chipselect = 1,
static struct resource sdhi_cn9_resources[] = {
[0] = {
.name = "SDHI",
.start = 0x04ce0000,
.end = 0x04ce01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdcard_cn9_device = {
.name = "spi_gpio",
.dev = {
.platform_data = &sdcard_cn9_platform_data,
static struct platform_device sdhi_cn9_device = {
.name = "sh_mobile_sdhi",
.num_resources = ARRAY_SIZE(sdhi_cn9_resources),
.resource = sdhi_cn9_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI,
},
};
......@@ -467,23 +474,24 @@ static struct platform_device *migor_devices[] __initdata = {
&migor_ceu_device,
&migor_nor_flash_device,
&migor_nand_flash_device,
&sdcard_cn9_device,
&sdhi_cn9_device,
&migor_camera[0],
&migor_camera[1],
};
static struct spi_board_info migor_spi_devices[] = {
{
.modalias = "mmc_spi",
.max_speed_hz = 5000000,
.chip_select = 0,
.controller_data = (void *) GPIO_PTD5,
},
};
extern char migor_sdram_enter_start;
extern char migor_sdram_enter_end;
extern char migor_sdram_leave_start;
extern char migor_sdram_leave_end;
static int __init migor_devices_setup(void)
{
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
&migor_sdram_enter_start,
&migor_sdram_enter_end,
&migor_sdram_leave_start,
&migor_sdram_leave_end);
#ifdef CONFIG_PM
/* Let D11 LED show STATUS0 */
gpio_request(GPIO_FN_STATUS0, NULL);
......@@ -525,6 +533,16 @@ static int __init migor_devices_setup(void)
gpio_request(GPIO_PTA1, NULL);
gpio_direction_input(GPIO_PTA1);
/* SDHI */
gpio_request(GPIO_FN_SDHICD, NULL);
gpio_request(GPIO_FN_SDHIWP, NULL);
gpio_request(GPIO_FN_SDHID3, NULL);
gpio_request(GPIO_FN_SDHID2, NULL);
gpio_request(GPIO_FN_SDHID1, NULL);
gpio_request(GPIO_FN_SDHID0, NULL);
gpio_request(GPIO_FN_SDHICMD, NULL);
gpio_request(GPIO_FN_SDHICLK, NULL);
/* Touch Panel */
gpio_request(GPIO_FN_IRQ6, NULL);
......@@ -612,9 +630,6 @@ static int __init migor_devices_setup(void)
i2c_register_board_info(0, migor_i2c_devices,
ARRAY_SIZE(migor_i2c_devices));
spi_register_board_info(migor_spi_devices,
ARRAY_SIZE(migor_spi_devices));
return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices));
}
arch_initcall(migor_devices_setup);
......
......@@ -116,7 +116,7 @@ static unsigned char irl2irq[R2D_NR_IRL];
int rts7751r2d_irq_demux(int irq)
{
if (irq >= R2D_NR_IRL || !irl2irq[irq])
if (irq >= R2D_NR_IRL || irq < 0 || !irl2irq[irq])
return irq;
return irl2irq[irq];
......
......@@ -16,15 +16,17 @@
#include <asm/io.h>
#include <mach-se/mach/se7722.h>
unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, };
static void disable_se7722_irq(unsigned int irq)
{
unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
unsigned int bit = (unsigned int)get_irq_chip_data(irq);
ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
}
static void enable_se7722_irq(unsigned int irq)
{
unsigned int bit = irq - SE7722_FPGA_IRQ_BASE;
unsigned int bit = (unsigned int)get_irq_chip_data(irq);
ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK);
}
......@@ -38,18 +40,15 @@ static struct irq_chip se7722_irq_chip __read_mostly = {
static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
{
unsigned short intv = ctrl_inw(IRQ01_STS);
struct irq_desc *ext_desc;
unsigned int ext_irq = SE7722_FPGA_IRQ_BASE;
unsigned int ext_irq = 0;
intv &= (1 << SE7722_FPGA_IRQ_NR) - 1;
while (intv) {
if (intv & 1) {
ext_desc = irq_desc + ext_irq;
handle_level_irq(ext_irq, ext_desc);
}
intv >>= 1;
ext_irq++;
for (; intv; intv >>= 1, ext_irq++) {
if (!(intv & 1))
continue;
generic_handle_irq(se7722_fpga_irq[ext_irq]);
}
}
......@@ -63,11 +62,18 @@ void __init init_se7722_IRQ(void)
ctrl_outw(0, IRQ01_MASK); /* disable all irqs */
ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */
for (i = 0; i < SE7722_FPGA_IRQ_NR; i++)
set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i,
for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
se7722_fpga_irq[i] = create_irq();
if (se7722_fpga_irq[i] < 0)
return;
set_irq_chip_and_handler_name(se7722_fpga_irq[i],
&se7722_irq_chip,
handle_level_irq, "level");
set_irq_chip_data(se7722_fpga_irq[i], (void *)i);
}
set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux);
set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
......
......@@ -60,8 +60,7 @@ static struct resource smc91x_eth_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SMC_IRQ,
.end = SMC_IRQ,
/* Filled in later */
.flags = IORESOURCE_IRQ,
},
};
......@@ -90,8 +89,7 @@ static struct resource cf_ide_resources[] = {
.flags = IORESOURCE_IO,
},
[2] = {
.start = MRSHPC_IRQ0,
.end = MRSHPC_IRQ0,
/* Filled in later */
.flags = IORESOURCE_IRQ,
},
};
......@@ -153,6 +151,14 @@ static struct platform_device *se7722_devices[] __initdata = {
static int __init se7722_devices_setup(void)
{
mrshpc_setup_windows();
/* Wire-up dynamic vectors */
cf_ide_resources[2].start = cf_ide_resources[2].end =
se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0];
smc91x_eth_resources[1].start = smc91x_eth_resources[1].end =
se7722_fpga_irq[SE7722_FPGA_IRQ_SMC];
return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
}
device_initcall(se7722_devices_setup);
......@@ -193,6 +199,5 @@ static void __init se7722_setup(char **cmdline_p)
static struct sh_machine_vector mv_se7722 __initmv = {
.mv_name = "Solution Engine 7722" ,
.mv_setup = se7722_setup ,
.mv_nr_irqs = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR,
.mv_init_irq = init_se7722_IRQ,
};
......@@ -7,4 +7,4 @@
#
#
obj-y := setup.o irq.o
\ No newline at end of file
obj-y := setup.o irq.o sdram.o
/*
* MS7724SE sdram self/auto-refresh setup code
*
* Copyright (C) 2009 Magnus Damm
*
* 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/sys.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/suspend.h>
#include <asm/romimage-macros.h>
/* code to enter and leave self-refresh. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(ms7724se_sdram_enter_start)
/* DBSC: put memory in self-refresh mode */
ED 0xFD000010, 0x00000000 /* DBEN */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000040, 0x00000001 /* DBRFPDN0 */
rts
nop
ENTRY(ms7724se_sdram_enter_end)
.balign 4
ENTRY(ms7724se_sdram_leave_start)
/* DBSC: put memory in auto-refresh mode */
ED 0xFD000040, 0x00000000 /* DBRFPDN0 */
WAIT 1
ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */
ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */
ED 0xFD000010, 0x00000001 /* DBEN */
ED 0xFD000040, 0x00010000 /* DBRFPDN0 */
rts
nop
ENTRY(ms7724se_sdram_leave_end)
......@@ -28,6 +28,7 @@
#include <asm/sh_eth.h>
#include <asm/clock.h>
#include <asm/sh_keysc.h>
#include <asm/suspend.h>
#include <cpu/sh7724.h>
#include <mach-se/mach/se7724.h>
......@@ -448,6 +449,52 @@ static struct platform_device sh7724_usb1_gadget_device = {
.resource = sh7724_usb1_gadget_resources,
};
static struct resource sdhi0_cn7_resources[] = {
[0] = {
.name = "SDHI0",
.start = 0x04ce0000,
.end = 0x04ce01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 101,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdhi0_cn7_device = {
.name = "sh_mobile_sdhi",
.id = 0,
.num_resources = ARRAY_SIZE(sdhi0_cn7_resources),
.resource = sdhi0_cn7_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI0,
},
};
static struct resource sdhi1_cn8_resources[] = {
[0] = {
.name = "SDHI1",
.start = 0x04cf0000,
.end = 0x04cf01ff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 24,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device sdhi1_cn8_device = {
.name = "sh_mobile_sdhi",
.id = 1,
.num_resources = ARRAY_SIZE(sdhi1_cn8_resources),
.resource = sdhi1_cn8_resources,
.archdata = {
.hwblk_id = HWBLK_SDHI1,
},
};
static struct platform_device *ms7724se_devices[] __initdata = {
&heartbeat_device,
&smc91x_eth_device,
......@@ -460,6 +507,8 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&sh7724_usb0_host_device,
&sh7724_usb1_gadget_device,
&fsi_device,
&sdhi0_cn7_device,
&sdhi1_cn8_device,
};
#define EEPROM_OP 0xBA206000
......@@ -484,7 +533,7 @@ static int __init sh_eth_is_eeprom_ready(void)
static void __init sh_eth_init(void)
{
int i;
u16 mac[3];
u16 mac;
/* check EEPROM status */
if (!sh_eth_is_eeprom_ready())
......@@ -498,16 +547,10 @@ static void __init sh_eth_init(void)
if (!sh_eth_is_eeprom_ready())
return;
mac[i] = ctrl_inw(EEPROM_DATA);
mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */
mac = ctrl_inw(EEPROM_DATA);
sh_eth_plat.mac_addr[i << 1] = mac & 0xff;
sh_eth_plat.mac_addr[(i << 1) + 1] = mac >> 8;
}
/* reset sh-eth */
ctrl_outl(0x1, SH_ETH_ADDR + 0x0);
/* set MAC addr */
ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR);
ctrl_outl((mac[2]), SH_ETH_MALR);
}
#define SW4140 0xBA201000
......@@ -524,11 +567,22 @@ static void __init sh_eth_init(void)
#define SW41_G 0x4000
#define SW41_H 0x8000
extern char ms7724se_sdram_enter_start;
extern char ms7724se_sdram_enter_end;
extern char ms7724se_sdram_leave_start;
extern char ms7724se_sdram_leave_end;
static int __init devices_setup(void)
{
u16 sw = ctrl_inw(SW4140); /* select camera, monitor */
struct clk *fsia_clk;
/* register board specific self-refresh code */
sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF,
&ms7724se_sdram_enter_start,
&ms7724se_sdram_enter_end,
&ms7724se_sdram_leave_start,
&ms7724se_sdram_leave_end);
/* Reset Release */
ctrl_outw(ctrl_inw(FPGA_OUT) &
~((1 << 1) | /* LAN */
......@@ -698,6 +752,26 @@ static int __init devices_setup(void)
clk_set_rate(&fsimcka_clk, 11000);
clk_put(fsia_clk);
/* SDHI0 connected to cn7 */
gpio_request(GPIO_FN_SDHI0CD, NULL);
gpio_request(GPIO_FN_SDHI0WP, NULL);
gpio_request(GPIO_FN_SDHI0D3, NULL);
gpio_request(GPIO_FN_SDHI0D2, NULL);
gpio_request(GPIO_FN_SDHI0D1, NULL);
gpio_request(GPIO_FN_SDHI0D0, NULL);
gpio_request(GPIO_FN_SDHI0CMD, NULL);
gpio_request(GPIO_FN_SDHI0CLK, NULL);
/* SDHI1 connected to cn8 */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1WP, NULL);
gpio_request(GPIO_FN_SDHI1D3, NULL);
gpio_request(GPIO_FN_SDHI1D2, NULL);
gpio_request(GPIO_FN_SDHI1D1, NULL);
gpio_request(GPIO_FN_SDHI1D0, NULL);
gpio_request(GPIO_FN_SDHI1CMD, NULL);
gpio_request(GPIO_FN_SDHI1CLK, NULL);
/*
* enable SH-Eth
*
......
......@@ -131,7 +131,7 @@ void decompress_kernel(void)
#ifdef CONFIG_SUPERH64
output_addr = (CONFIG_MEMORY_START + 0x2000);
#else
output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE);
output_addr = __pa((unsigned long)&_text+PAGE_SIZE);
#ifdef CONFIG_29BIT
output_addr |= P2SEG;
#endif
......
......@@ -13,7 +13,6 @@
#include <linux/init.h>
#include <linux/sysdev.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/string.h>
#include <asm/dma.h>
......@@ -21,7 +20,6 @@
static struct sysdev_class dma_sysclass = {
.name = "dma",
};
EXPORT_SYMBOL(dma_sysclass);
static ssize_t dma_show_devices(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
......
config PCI
bool "PCI support"
depends on SYS_SUPPORTS_PCI
help
Find out whether you have a PCI motherboard. PCI is the name of a
bus system, i.e. the way the CPU talks to the other stuff inside
your box. If you have PCI, say Y, otherwise N.
config SH_PCIDMA_NONCOHERENT
bool "Cache and PCI noncoherent"
depends on PCI
default y
help
Enable this option if your platform does not have a CPU cache which
remains coherent with PCI DMA. It is safest to say 'Y', although you
will see better performance if you can say 'N', because the PCI DMA
code will not have to flush the CPU's caches. If you have a PCI host
bridge integrated with your SH CPU, refer carefully to the chip specs
to see if you can say 'N' here. Otherwise, leave it as 'Y'.
......@@ -28,9 +28,6 @@
/* Returns the privileged segment base of a given address */
#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
/* Returns the physical address of a PnSEG (n=1,2) address */
#define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff)
#if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED)
/*
* Map an address to a certain privileged segment
......@@ -60,5 +57,11 @@
#define P3_ADDR_MAX P4SEG
#endif
#ifndef __ASSEMBLY__
#ifdef CONFIG_PMB
extern int __in_29bit_mode(void);
#endif /* CONFIG_PMB */
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_ADDRSPACE_H */
......@@ -78,11 +78,10 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
/* Atomic operations are already serializing on SH */
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
#define smp_mb__before_atomic_inc() barrier()
#define smp_mb__after_atomic_inc() barrier()
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
#define smp_mb__before_atomic_inc() smp_mb()
#define smp_mb__after_atomic_inc() smp_mb()
#include <asm-generic/atomic-long.h>
#include <asm-generic/atomic64.h>
......
......@@ -26,8 +26,8 @@
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
#define smp_mb__before_clear_bit() smp_mb()
#define smp_mb__after_clear_bit() smp_mb()
#ifdef CONFIG_SUPERH32
static inline unsigned long ffz(unsigned long word)
......
......@@ -14,11 +14,15 @@
#include <asm/processor.h>
extern void select_idle_routine(void);
static void __init check_bugs(void)
{
extern unsigned long loops_per_jiffy;
char *p = &init_utsname()->machine[2]; /* "sh" */
select_idle_routine();
current_cpu_data.loops_per_jiffy = loops_per_jiffy;
switch (current_cpu_data.family) {
......
#ifndef __ASM_SH_DMA_MAPPING_H
#define __ASM_SH_DMA_MAPPING_H
#include <linux/mm.h>
#include <linux/scatterlist.h>
#include <linux/dma-debug.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
extern struct dma_map_ops *dma_ops;
extern void no_iommu_init(void);
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
return dma_ops;
}
#include <asm-generic/dma-coherent.h>
#include <asm-generic/dma-mapping-common.h>
static inline int dma_supported(struct device *dev, u64 mask)
{
struct dma_map_ops *ops = get_dma_ops(dev);
extern struct bus_type pci_bus_type;
if (ops->dma_supported)
return ops->dma_supported(dev, mask);
#define dma_supported(dev, mask) (1)
return 1;
}
static inline int dma_set_mask(struct device *dev, u64 mask)
{
struct dma_map_ops *ops = get_dma_ops(dev);
if (!dev->dma_mask || !dma_supported(dev, mask))
return -EIO;
if (ops->set_dma_mask)
return ops->set_dma_mask(dev, mask);
*dev->dma_mask = mask;
return 0;
}
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag);
void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle);
void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
enum dma_data_direction dir);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
#define dma_is_consistent(d, h) (1)
static inline dma_addr_t dma_map_single(struct device *dev,
void *ptr, size_t size,
enum dma_data_direction dir)
{
dma_addr_t addr = virt_to_phys(ptr);
#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
if (dev->bus == &pci_bus_type)
return addr;
#endif
dma_cache_sync(dev, ptr, size, dir);
debug_dma_map_page(dev, virt_to_page(ptr),
(unsigned long)ptr & ~PAGE_MASK, size,
dir, addr, true);
return addr;
}
static inline void dma_unmap_single(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
debug_dma_unmap_page(dev, addr, size, dir, true);
}
static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
int i;
for (i = 0; i < nents; i++) {
#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
#ifdef CONFIG_DMA_COHERENT
#define dma_is_consistent(d, h) (1)
#else
#define dma_is_consistent(d, h) (0)
#endif
sg[i].dma_address = sg_phys(&sg[i]);
sg[i].dma_length = sg[i].length;
}
debug_dma_map_sg(dev, sg, nents, i, dir);
return nents;
}
static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir)
{
debug_dma_unmap_sg(dev, sg, nents, dir);
}
static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir)
{
return dma_map_single(dev, page_address(page) + offset, size, dir);
}
static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
size_t size, enum dma_data_direction dir)
{
dma_unmap_single(dev, dma_address, size, dir);
}
static inline void __dma_sync_single(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir)
static inline int dma_get_cache_alignment(void)
{
#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
if (dev->bus == &pci_bus_type)
return;
#endif
dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir);
/*
* Each processor family will define its own L1_CACHE_SHIFT,
* L1_CACHE_BYTES wraps to this, so this is always safe.
*/
return L1_CACHE_BYTES;
}
static inline void dma_sync_single_range(struct device *dev,
dma_addr_t dma_handle,
unsigned long offset, size_t size,
enum dma_data_direction dir)
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
#if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT)
if (dev->bus == &pci_bus_type)
return;
#endif
dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir);
}
struct dma_map_ops *ops = get_dma_ops(dev);
static inline void __dma_sync_sg(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir)
{
int i;
if (ops->mapping_error)
return ops->mapping_error(dev, dma_addr);
for (i = 0; i < nelems; i++) {
#if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT)
dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir);
#endif
sg[i].dma_address = sg_phys(&sg[i]);
sg[i].dma_length = sg[i].length;
}
return dma_addr == 0;
}
static inline void dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir)
static inline void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp)
{
__dma_sync_single(dev, dma_handle, size, dir);
debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir);
}
struct dma_map_ops *ops = get_dma_ops(dev);
void *memory;
static inline void dma_sync_single_for_device(struct device *dev,
dma_addr_t dma_handle,
size_t size,
enum dma_data_direction dir)
{
__dma_sync_single(dev, dma_handle, size, dir);
debug_dma_sync_single_for_device(dev, dma_handle, size, dir);
}
if (dma_alloc_from_coherent(dev, size, dma_handle, &memory))
return memory;
if (!ops->alloc_coherent)
return NULL;
static inline void dma_sync_single_range_for_cpu(struct device *dev,
dma_addr_t dma_handle,
unsigned long offset,
size_t size,
enum dma_data_direction direction)
{
dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction);
debug_dma_sync_single_range_for_cpu(dev, dma_handle,
offset, size, direction);
}
memory = ops->alloc_coherent(dev, size, dma_handle, gfp);
debug_dma_alloc_coherent(dev, size, *dma_handle, memory);
static inline void dma_sync_single_range_for_device(struct device *dev,
dma_addr_t dma_handle,
unsigned long offset,
size_t size,
enum dma_data_direction direction)
{
dma_sync_single_for_device(dev, dma_handle+offset, size, direction);
debug_dma_sync_single_range_for_device(dev, dma_handle,
offset, size, direction);
return memory;
}
static inline void dma_sync_sg_for_cpu(struct device *dev,
struct scatterlist *sg, int nelems,
enum dma_data_direction dir)
static inline void dma_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle)
{
__dma_sync_sg(dev, sg, nelems, dir);
debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir);
}
struct dma_map_ops *ops = get_dma_ops(dev);
static inline void dma_sync_sg_for_device(struct device *dev,
struct scatterlist *sg, int nelems,
enum dma_data_direction dir)
{
__dma_sync_sg(dev, sg, nelems, dir);
debug_dma_sync_sg_for_device(dev, sg, nelems, dir);
}
WARN_ON(irqs_disabled()); /* for portability */
static inline int dma_get_cache_alignment(void)
{
/*
* Each processor family will define its own L1_CACHE_SHIFT,
* L1_CACHE_BYTES wraps to this, so this is always safe.
*/
return L1_CACHE_BYTES;
}
if (dma_release_from_coherent(dev, get_order(size), vaddr))
return;
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return dma_addr == 0;
debug_dma_free_coherent(dev, size, vaddr, dma_handle);
if (ops->free_coherent)
ops->free_coherent(dev, size, vaddr, dma_handle);
}
#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
extern int
dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
dma_addr_t device_addr, size_t size, int flags);
extern void
dma_release_declared_memory(struct device *dev);
extern void *
dma_mark_declared_memory_occupied(struct device *dev,
dma_addr_t device_addr, size_t size);
/* arch/sh/mm/consistent.c */
extern void *dma_generic_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_addr, gfp_t flag);
extern void dma_generic_free_coherent(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle);
#endif /* __ASM_SH_DMA_MAPPING_H */
......@@ -194,6 +194,12 @@
#define DWARF_ARCH_RA_REG 17
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
#include <linux/bug.h>
#include <linux/list.h>
#include <linux/module.h>
/*
* Read either the frame pointer (r14) or the stack pointer (r15).
* NOTE: this MUST be inlined.
......@@ -241,6 +247,12 @@ struct dwarf_cie {
unsigned long flags;
#define DWARF_CIE_Z_AUGMENTATION (1 << 0)
/*
* 'mod' will be non-NULL if this CIE came from a module's
* .eh_frame section.
*/
struct module *mod;
};
/**
......@@ -255,6 +267,12 @@ struct dwarf_fde {
unsigned char *instructions;
unsigned char *end;
struct list_head link;
/*
* 'mod' will be non-NULL if this FDE came from a module's
* .eh_frame section.
*/
struct module *mod;
};
/**
......@@ -364,6 +382,12 @@ static inline unsigned int DW_CFA_operand(unsigned long insn)
extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
struct dwarf_frame *);
extern void dwarf_free_frame(struct dwarf_frame *);
extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *,
struct module *);
extern void module_dwarf_cleanup(struct module *);
#endif /* !__ASSEMBLY__ */
#define CFI_STARTPROC .cfi_startproc
......@@ -391,6 +415,10 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long,
static inline void dwarf_unwinder_init(void)
{
}
#define module_dwarf_finalize(hdr, sechdrs, me) (0)
#define module_dwarf_cleanup(mod) do { } while (0)
#endif
#endif /* CONFIG_DWARF_UNWINDER */
......
......@@ -14,9 +14,9 @@
#define _ASM_FIXMAP_H
#include <linux/kernel.h>
#include <linux/threads.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
#include <linux/threads.h>
#include <asm/kmap_types.h>
#endif
......@@ -46,9 +46,9 @@
* fix-mapped?
*/
enum fixed_addresses {
#define FIX_N_COLOURS 16
#define FIX_N_COLOURS 8
FIX_CMAP_BEGIN,
FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS,
FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS),
FIX_UNCACHED,
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
......
......@@ -35,4 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr)
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_FUNCTION_TRACER */
#ifndef __ASSEMBLY__
/* arch/sh/kernel/return_address.c */
extern void *return_address(unsigned int);
#define HAVE_ARCH_CALLER_ADDR
#define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0))
#define CALLER_ADDR1 ((unsigned long)return_address(1))
#define CALLER_ADDR2 ((unsigned long)return_address(2))
#define CALLER_ADDR3 ((unsigned long)return_address(3))
#define CALLER_ADDR4 ((unsigned long)return_address(4))
#define CALLER_ADDR5 ((unsigned long)return_address(5))
#define CALLER_ADDR6 ((unsigned long)return_address(6))
#endif /* __ASSEMBLY__ */
#endif /* __ASM_SH_FTRACE_H */
#ifndef __ASM_SH_HARDIRQ_H
#define __ASM_SH_HARDIRQ_H
extern void ack_bad_irq(unsigned int irq);
#define ack_bad_irq ack_bad_irq
#include <linux/threads.h>
#include <linux/irq.h>
typedef struct {
unsigned int __softirq_pending;
unsigned int __nmi_count; /* arch dependent */
} ____cacheline_aligned irq_cpustat_t;
#include <asm-generic/hardirq.h>
#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
extern void ack_bad_irq(unsigned int irq);
#endif /* __ASM_SH_HARDIRQ_H */
......@@ -90,15 +90,11 @@
#define ctrl_outl __raw_writel
#define ctrl_outq __raw_writeq
extern unsigned long generic_io_base;
static inline void ctrl_delay(void)
{
#ifdef CONFIG_CPU_SH4
__raw_readw(CCN_PVR);
#elif defined(P2SEG)
__raw_readw(P2SEG);
#else
#error "Need a dummy address for delay"
#endif
__raw_readw(generic_io_base);
}
#define __BUILD_MEMORY_STRING(bwlq, type) \
......@@ -186,8 +182,6 @@ __BUILD_MEMORY_STRING(q, u64)
#define IO_SPACE_LIMIT 0xffffffff
extern unsigned long generic_io_base;
/*
* This function provides a method for the generic case where a
* board-specific ioport_map simply needs to return the port + some
......@@ -246,7 +240,7 @@ void __iounmap(void __iomem *addr);
static inline void __iomem *
__ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
{
#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
unsigned long last_addr = offset + size - 1;
#endif
void __iomem *ret;
......@@ -255,7 +249,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
if (ret)
return ret;
#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED)
#if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB)
/*
* For P1 and P2 space this is trivial, as everything is already
* mapped. Uncached access for P1 addresses are done through P2.
......
#ifndef __ASM_SH_IRQFLAGS_H
#define __ASM_SH_IRQFLAGS_H
#ifdef CONFIG_SUPERH32
#include "irqflags_32.h"
#else
#include "irqflags_64.h"
#endif
#define RAW_IRQ_DISABLED 0xf0
#define RAW_IRQ_ENABLED 0x00
#define raw_local_save_flags(flags) \
do { (flags) = __raw_local_save_flags(); } while (0)
static inline int raw_irqs_disabled_flags(unsigned long flags)
{
return (flags != 0);
}
static inline int raw_irqs_disabled(void)
{
unsigned long flags = __raw_local_save_flags();
return raw_irqs_disabled_flags(flags);
}
#define raw_local_irq_save(flags) \
do { (flags) = __raw_local_irq_save(); } while (0)
static inline void raw_local_irq_restore(unsigned long flags)
{
if ((flags & 0xf0) != 0xf0)
raw_local_irq_enable();
}
#include <asm-generic/irqflags.h>
#endif /* __ASM_SH_IRQFLAGS_H */
#ifndef __ASM_SH_IRQFLAGS_32_H
#define __ASM_SH_IRQFLAGS_32_H
static inline void raw_local_irq_enable(void)
{
unsigned long __dummy0, __dummy1;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"and %1, %0\n\t"
#ifdef CONFIG_CPU_HAS_SR_RB
"stc r6_bank, %1\n\t"
"or %1, %0\n\t"
#endif
"ldc %0, sr\n\t"
: "=&r" (__dummy0), "=r" (__dummy1)
: "1" (~0x000000f0)
: "memory"
);
}
static inline void raw_local_irq_disable(void)
{
unsigned long flags;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"or #0xf0, %0\n\t"
"ldc %0, sr\n\t"
: "=&z" (flags)
: /* no inputs */
: "memory"
);
}
static inline void set_bl_bit(void)
{
unsigned long __dummy0, __dummy1;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"or %2, %0\n\t"
"and %3, %0\n\t"
"ldc %0, sr\n\t"
: "=&r" (__dummy0), "=r" (__dummy1)
: "r" (0x10000000), "r" (0xffffff0f)
: "memory"
);
}
static inline void clear_bl_bit(void)
{
unsigned long __dummy0, __dummy1;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"and %2, %0\n\t"
"ldc %0, sr\n\t"
: "=&r" (__dummy0), "=r" (__dummy1)
: "1" (~0x10000000)
: "memory"
);
}
static inline unsigned long __raw_local_save_flags(void)
{
unsigned long flags;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"and #0xf0, %0\n\t"
: "=&z" (flags)
: /* no inputs */
: "memory"
);
return flags;
}
static inline unsigned long __raw_local_irq_save(void)
{
unsigned long flags, __dummy;
__asm__ __volatile__ (
"stc sr, %1\n\t"
"mov %1, %0\n\t"
"or #0xf0, %0\n\t"
"ldc %0, sr\n\t"
"mov %1, %0\n\t"
"and #0xf0, %0\n\t"
: "=&z" (flags), "=&r" (__dummy)
: /* no inputs */
: "memory"
);
return flags;
}
#endif /* __ASM_SH_IRQFLAGS_32_H */
#ifndef __ASM_SH_IRQFLAGS_64_H
#define __ASM_SH_IRQFLAGS_64_H
#include <cpu/registers.h>
#define SR_MASK_LL 0x00000000000000f0LL
#define SR_BL_LL 0x0000000010000000LL
static inline void raw_local_irq_enable(void)
{
unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"and %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
static inline void raw_local_irq_disable(void)
{
unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"or %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
static inline void set_bl_bit(void)
{
unsigned long long __dummy0, __dummy1 = SR_BL_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"or %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
static inline void clear_bl_bit(void)
{
unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"and %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
static inline unsigned long __raw_local_save_flags(void)
{
unsigned long long __dummy = SR_MASK_LL;
unsigned long flags;
__asm__ __volatile__ (
"getcon " __SR ", %0\n\t"
"and %0, %1, %0"
: "=&r" (flags)
: "r" (__dummy));
return flags;
}
static inline unsigned long __raw_local_irq_save(void)
{
unsigned long long __dummy0, __dummy1 = SR_MASK_LL;
unsigned long flags;
__asm__ __volatile__ (
"getcon " __SR ", %1\n\t"
"or %1, r63, %0\n\t"
"or %1, %2, %1\n\t"
"putcon %1, " __SR "\n\t"
"and %0, %2, %0"
: "=&r" (flags), "=&r" (__dummy0)
: "r" (__dummy1));
return flags;
}
#endif /* __ASM_SH_IRQFLAGS_64_H */
......@@ -7,12 +7,16 @@
#define PMB_PASCR 0xff000070
#define PMB_IRMCR 0xff000078
#define PASCR_SE 0x80000000
#define PMB_ADDR 0xf6100000
#define PMB_DATA 0xf7100000
#define PMB_ENTRY_MAX 16
#define PMB_E_MASK 0x0000000f
#define PMB_E_SHIFT 8
#define PMB_PFN_MASK 0xff000000
#define PMB_SZ_16M 0x00000000
#define PMB_SZ_64M 0x00000010
#define PMB_SZ_128M 0x00000080
......@@ -62,17 +66,10 @@ struct pmb_entry {
};
/* arch/sh/mm/pmb.c */
int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
unsigned long flags, int *entry);
int set_pmb_entry(struct pmb_entry *pmbe);
void clear_pmb_entry(struct pmb_entry *pmbe);
struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
unsigned long flags);
void pmb_free(struct pmb_entry *pmbe);
long pmb_remap(unsigned long virt, unsigned long phys,
unsigned long size, unsigned long flags);
void pmb_unmap(unsigned long addr);
int pmb_init(void);
#endif /* __ASSEMBLY__ */
#endif /* __MMU_H */
......@@ -3,8 +3,6 @@
#ifdef __KERNEL__
#include <linux/dma-mapping.h>
/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
......@@ -54,30 +52,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
* address space. The networking and block device layers use
* this boolean for bounce buffer decisions.
*/
#define PCI_DMA_BUS_IS_PHYS (1)
#include <linux/types.h>
#include <linux/slab.h>
#include <asm/scatterlist.h>
#include <linux/string.h>
#include <asm/io.h>
#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys)
/* pci_unmap_{single,page} being a nop depends upon the
* configuration.
*/
#ifdef CONFIG_SH_PCIDMA_NONCOHERENT
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \
dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \
__u32 LEN_NAME;
#define pci_unmap_addr(PTR, ADDR_NAME) \
((PTR)->ADDR_NAME)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \
(((PTR)->ADDR_NAME) = (VAL))
#define pci_unmap_len(PTR, LEN_NAME) \
((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) \
(((PTR)->LEN_NAME) = (VAL))
#ifdef CONFIG_DMA_NONCOHERENT
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME;
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME;
#define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME)
#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL))
#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
#else
#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
......
#ifndef __ASM_SH_PERF_EVENT_H
#define __ASM_SH_PERF_EVENT_H
/* SH only supports software events through this interface. */
static inline void set_perf_event_pending(void) {}
struct hw_perf_event;
#define MAX_HWEVENTS 2
struct sh_pmu {
const char *name;
unsigned int num_events;
void (*disable_all)(void);
void (*enable_all)(void);
void (*enable)(struct hw_perf_event *, int);
void (*disable)(struct hw_perf_event *, int);
u64 (*read)(int);
int (*event_map)(int);
unsigned int max_events;
unsigned long raw_event_mask;
const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX];
};
/* arch/sh/kernel/perf_event.c */
extern int register_sh_pmu(struct sh_pmu *);
extern int reserve_pmc_hardware(void);
extern void release_pmc_hardware(void);
static inline void set_perf_event_pending(void)
{
/* Nothing to see here, move along. */
}
#define PERF_EVENT_INDEX_OFFSET 0
......
......@@ -75,13 +75,31 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
#define FIRST_USER_ADDRESS 0
#ifdef CONFIG_32BIT
#define PHYS_ADDR_MASK 0xffffffff
#define PHYS_ADDR_MASK29 0x1fffffff
#define PHYS_ADDR_MASK32 0xffffffff
#ifdef CONFIG_PMB
static inline unsigned long phys_addr_mask(void)
{
/* Is the MMU in 29bit mode? */
if (__in_29bit_mode())
return PHYS_ADDR_MASK29;
return PHYS_ADDR_MASK32;
}
#elif defined(CONFIG_32BIT)
static inline unsigned long phys_addr_mask(void)
{
return PHYS_ADDR_MASK32;
}
#else
#define PHYS_ADDR_MASK 0x1fffffff
static inline unsigned long phys_addr_mask(void)
{
return PHYS_ADDR_MASK29;
}
#endif
#define PTE_PHYS_MASK (PHYS_ADDR_MASK & PAGE_MASK)
#define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK)
#define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT)
#ifdef CONFIG_SUPERH32
......
......@@ -108,7 +108,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x)
#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
#define _PAGE_FLAGS_HARDWARE_MASK (PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS))
#define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS))
/* Hardware flags, page size encoding */
#if !defined(CONFIG_MMU)
......
#ifndef __ASM_SH_SCATTERLIST_H
#define __ASM_SH_SCATTERLIST_H
#define ISA_DMA_THRESHOLD PHYS_ADDR_MASK
#define ISA_DMA_THRESHOLD phys_addr_mask()
#include <asm-generic/scatterlist.h>
......
......@@ -2,6 +2,7 @@
#define _ASM_SH_SUSPEND_H
#ifndef __ASSEMBLY__
#include <linux/notifier.h>
static inline int arch_prepare_suspend(void) { return 0; }
#include <asm/ptrace.h>
......@@ -19,6 +20,69 @@ void sh_mobile_setup_cpuidle(void);
static inline void sh_mobile_setup_cpuidle(void) {}
#endif
/* notifier chains for pre/post sleep hooks */
extern struct atomic_notifier_head sh_mobile_pre_sleep_notifier_list;
extern struct atomic_notifier_head sh_mobile_post_sleep_notifier_list;
/* priority levels for notifiers */
#define SH_MOBILE_SLEEP_BOARD 0
#define SH_MOBILE_SLEEP_CPU 1
#define SH_MOBILE_PRE(x) (x)
#define SH_MOBILE_POST(x) (-(x))
/* board code registration function for self-refresh assembly snippets */
void sh_mobile_register_self_refresh(unsigned long flags,
void *pre_start, void *pre_end,
void *post_start, void *post_end);
/* register structure for address/data information */
struct sh_sleep_regs {
unsigned long stbcr;
unsigned long bar;
/* MMU */
unsigned long pteh;
unsigned long ptel;
unsigned long ttb;
unsigned long tea;
unsigned long mmucr;
unsigned long ptea;
unsigned long pascr;
unsigned long irmcr;
/* Cache */
unsigned long ccr;
unsigned long ramcr;
};
/* data area for low-level sleep code */
struct sh_sleep_data {
/* current sleep mode (SUSP_SH_...) */
unsigned long mode;
/* addresses of board specific self-refresh snippets */
unsigned long sf_pre;
unsigned long sf_post;
/* address of resume code */
unsigned long resume;
/* register state saved and restored by the assembly code */
unsigned long vbr;
unsigned long spc;
unsigned long sr;
unsigned long sp;
/* structure for keeping register addresses */
struct sh_sleep_regs addr;
/* structure for saving/restoring register state */
struct sh_sleep_regs data;
};
/* a bitmap of supported sleep modes (SUSP_SH..) */
extern unsigned long sh_mobile_sleep_supported;
#endif
/* flags passed to assembly suspend code */
......@@ -27,5 +91,6 @@ static inline void sh_mobile_setup_cpuidle(void) {}
#define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */
#define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */
#define SUSP_SH_SF (1 << 4) /* Enable self-refresh */
#define SUSP_SH_MMU (1 << 5) /* Save/restore MMU and cache */
#endif /* _ASM_SH_SUSPEND_H */
......@@ -171,10 +171,6 @@ BUILD_TRAP_HANDLER(fpu_error);
BUILD_TRAP_HANDLER(fpu_state_restore);
BUILD_TRAP_HANDLER(nmi);
#ifdef CONFIG_BUG
extern void handle_BUG(struct pt_regs *);
#endif
#define arch_align_stack(x) (x)
struct mem_access {
......
......@@ -232,4 +232,33 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs __regs);
static inline void set_bl_bit(void)
{
unsigned long __dummy0, __dummy1;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"or %2, %0\n\t"
"and %3, %0\n\t"
"ldc %0, sr\n\t"
: "=&r" (__dummy0), "=r" (__dummy1)
: "r" (0x10000000), "r" (0xffffff0f)
: "memory"
);
}
static inline void clear_bl_bit(void)
{
unsigned long __dummy0, __dummy1;
__asm__ __volatile__ (
"stc sr, %0\n\t"
"and %2, %0\n\t"
"ldc %0, sr\n\t"
: "=&r" (__dummy0), "=r" (__dummy1)
: "1" (~0x10000000)
: "memory"
);
}
#endif /* __ASM_SH_SYSTEM_32_H */
......@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <cpu/registers.h>
#include <asm/processor.h>
/*
......@@ -47,4 +48,29 @@ static inline reg_size_t register_align(void *val)
return (unsigned long long)(signed long long)(signed long)val;
}
#define SR_BL_LL 0x0000000010000000LL
static inline void set_bl_bit(void)
{
unsigned long long __dummy0, __dummy1 = SR_BL_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"or %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
static inline void clear_bl_bit(void)
{
unsigned long long __dummy0, __dummy1 = ~SR_BL_LL;
__asm__ __volatile__("getcon " __SR ", %0\n\t"
"and %0, %1, %0\n\t"
"putcon %0, " __SR "\n\t"
: "=&r" (__dummy0)
: "r" (__dummy1));
}
#endif /* __ASM_SH_SYSTEM_64_H */
......@@ -19,6 +19,7 @@ struct thread_info {
struct task_struct *task; /* main task structure */
struct exec_domain *exec_domain; /* execution domain */
unsigned long flags; /* low level flags */
__u32 status; /* thread synchronous flags */
__u32 cpu;
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit; /* thread address space */
......@@ -111,7 +112,6 @@ extern void free_thread_info(struct thread_info *ti);
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */
#define TIF_SINGLESTEP 4 /* singlestepping active */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SECCOMP 6 /* secure computing */
......@@ -125,7 +125,6 @@ extern void free_thread_info(struct thread_info *ti);
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
......@@ -149,13 +148,32 @@ extern void free_thread_info(struct thread_info *ti);
/* work to do on any return to u-space */
#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \
_TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \
_TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \
_TIF_NOTIFY_RESUME | _TIF_SYSCALL_TRACEPOINT)
_TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \
_TIF_SYSCALL_TRACEPOINT)
/* work to do on interrupt/exception return */
#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \
_TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP))
/*
* Thread-synchronous status.
*
* This is different from the flags in that nobody else
* ever touches our thread-synchronous status, so we don't
* have to worry about atomic accesses.
*/
#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */
#ifndef __ASSEMBLY__
#define HAVE_SET_RESTORE_SIGMASK 1
static inline void set_restore_sigmask(void)
{
struct thread_info *ti = current_thread_info();
ti->status |= TS_RESTORE_SIGMASK;
set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags);
}
#endif /* !__ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_THREAD_INFO_H */
......@@ -40,6 +40,14 @@
#endif
#define mc_capable() (1)
const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
extern cpumask_t cpu_core_map[NR_CPUS];
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
#include <asm-generic/topology.h>
#endif /* _ASM_SH_TOPOLOGY_H */
......@@ -60,16 +60,5 @@
#define BRCR_UBDE (1 << 0)
#endif
#ifndef __ASSEMBLY__
/* arch/sh/kernel/cpu/ubc.S */
extern void ubc_sleep(void);
#ifdef CONFIG_UBC_WAKEUP
extern void ubc_wakeup(void);
#else
#define ubc_wakeup() do { } while (0)
#endif
#endif
#endif /* __KERNEL__ */
#endif /* __ASM_SH_UBC_H */
......@@ -2,6 +2,8 @@
* include/asm-sh/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
* Copyright (C) 2009 Siemens AG
* Copyright (C) 2009 Valentin Sitdikov
*
* 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
......@@ -61,6 +63,61 @@
#define WTCSR_CKS_2048 0x06
#define WTCSR_CKS_4096 0x07
#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
/**
* sh_wdt_read_cnt - Read from Counter
* Reads back the WTCNT value.
*/
static inline __u32 sh_wdt_read_cnt(void)
{
return ctrl_inl(WTCNT_R);
}
/**
* sh_wdt_write_cnt - Write to Counter
* @val: Value to write
*
* Writes the given value @val to the lower byte of the timer counter.
* The upper byte is set manually on each write.
*/
static inline void sh_wdt_write_cnt(__u32 val)
{
ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT);
}
/**
* sh_wdt_write_bst - Write to Counter
* @val: Value to write
*
* Writes the given value @val to the lower byte of the timer counter.
* The upper byte is set manually on each write.
*/
static inline void sh_wdt_write_bst(__u32 val)
{
ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST);
}
/**
* sh_wdt_read_csr - Read from Control/Status Register
*
* Reads back the WTCSR value.
*/
static inline __u32 sh_wdt_read_csr(void)
{
return ctrl_inl(WTCSR_R);
}
/**
* sh_wdt_write_csr - Write to Control/Status Register
* @val: Value to write
*
* Writes the given value @val to the lower byte of the control/status
* register. The upper byte is set manually on each write.
*/
static inline void sh_wdt_write_csr(__u32 val)
{
ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR);
}
#else
/**
* sh_wdt_read_cnt - Read from Counter
* Reads back the WTCNT value.
......@@ -103,6 +160,6 @@ static inline void sh_wdt_write_csr(__u8 val)
{
ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR);
}
#endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */
#endif /* __KERNEL__ */
#endif /* __ASM_SH_WATCHDOG_H */
......@@ -2,6 +2,8 @@
* include/asm-sh/cpu-sh4/watchdog.h
*
* Copyright (C) 2002, 2003 Paul Mundt
* Copyright (C) 2009 Siemens AG
* Copyright (C) 2009 Sitdikov Valentin
*
* 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
......@@ -10,9 +12,20 @@
#ifndef __ASM_CPU_SH4_WATCHDOG_H
#define __ASM_CPU_SH4_WATCHDOG_H
#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780)
/* Prefix definition */
#define WTBST_HIGH 0x55
/* Register definitions */
#define WTCNT_R 0xffcc0010 /*WDTCNT*/
#define WTCSR 0xffcc0004 /*WDTCSR*/
#define WTCNT 0xffcc0000 /*WDTST*/
#define WTST WTCNT
#define WTBST 0xffcc0008 /*WDTBST*/
#else
/* Register definitions */
#define WTCNT 0xffc00008
#define WTCSR 0xffc0000c
#endif
/* Bit definitions */
#define WTCSR_TME 0x80
......
......@@ -92,18 +92,11 @@
#define SE7722_FPGA_IRQ_MRSHPC1 3 /* IRQ1 */
#define SE7722_FPGA_IRQ_MRSHPC2 4 /* IRQ1 */
#define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */
#define SE7722_FPGA_IRQ_NR 6
#define SE7722_FPGA_IRQ_BASE 110
#define MRSHPC_IRQ3 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3)
#define MRSHPC_IRQ2 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2)
#define MRSHPC_IRQ1 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1)
#define MRSHPC_IRQ0 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0)
#define SMC_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC)
#define USB_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB)
/* arch/sh/boards/se/7722/irq.c */
extern unsigned int se7722_fpga_irq[];
void init_se7722_IRQ(void);
#define __IO_PREFIX se7722
......
......@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
endif
obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \
machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \
CFLAGS_REMOVE_return_address.o = -pg
obj-y := debugtraps.o dma-nommu.o dumpstack.o \
idle.o io.o io_generic.o irq.o \
irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \
ptrace_$(BITS).o return_address.o \
setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \
syscalls_$(BITS).o time.o topology.o traps.o \
traps_$(BITS).o unwinder.o
......@@ -35,6 +39,7 @@ obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
......
......@@ -34,5 +34,28 @@ int main(void)
DEFINE(PBE_NEXT, offsetof(struct pbe, next));
DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs));
#endif
DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode));
DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre));
DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post));
DEFINE(SH_SLEEP_RESUME, offsetof(struct sh_sleep_data, resume));
DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr));
DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc));
DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr));
DEFINE(SH_SLEEP_SP, offsetof(struct sh_sleep_data, sp));
DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr));
DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data));
DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr));
DEFINE(SH_SLEEP_REG_BAR, offsetof(struct sh_sleep_regs, bar));
DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh));
DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel));
DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb));
DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea));
DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr));
DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea));
DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr));
DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr));
DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr));
DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr));
return 0;
}
......@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/
# Common interfaces.
obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o
......
......@@ -338,17 +338,6 @@ asmlinkage void __init sh_cpu_init(void)
}
#endif
/*
* Some brain-damaged loaders decided it would be a good idea to put
* the UBC to sleep. This causes some issues when it comes to things
* like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So ..
* we wake it up and hope that all is well.
*/
#ifdef CONFIG_SUPERH32
if (raw_smp_processor_id() == 0)
ubc_wakeup();
#endif
speculative_execution_init();
expmask_init();
}
......@@ -297,41 +297,8 @@ ENTRY(vbr_base)
!
.balign 256,0,256
general_exception:
#ifndef CONFIG_CPU_SUBTYPE_SHX3
bra handle_exception
sts pr, k3 ! save original pr value in k3
#else
mov.l 1f, k4
mov.l @k4, k4
! Is EXPEVT larger than 0x800?
mov #0x8, k0
shll8 k0
cmp/hs k0, k4
bf 0f
! then add 0x580 (k2 is 0xd80 or 0xda0)
mov #0x58, k0
shll2 k0
shll2 k0
add k0, k4
0:
! Setup stack and save DSP context (k0 contains original r15 on return)
bsr prepare_stack
nop
! Save registers / Switch to bank 0
mov k4, k2 ! keep vector in k2
mov.l 1f, k4 ! SR bits to clear in k4
bsr save_regs ! needs original pr value in k3
nop
bra handle_exception_special
nop
.align 2
1: .long EXPEVT
#endif
! prepare_stack()
! - roll back gRB
......
......@@ -9,6 +9,11 @@ obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o)
obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
# Perf events
perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o
perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o
# CPU subtype setup
obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o
......@@ -27,4 +32,5 @@ endif
# Additional clocks by subtype
clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o
obj-y += $(clock-y)
obj-y += $(clock-y)
obj-$(CONFIG_PERF_EVENTS) += $(perf-y)
/*
* arch/sh/oprofile/op_model_sh7750.c
* Performance events support for SH7750-style performance counters
*
* OProfile support for SH7750/SH7750S Performance Counters
*
* Copyright (C) 2003 - 2008 Paul Mundt
* Copyright (C) 2009 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/kernel.h>
#include <linux/oprofile.h>
#include <linux/profile.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/fs.h>
#include "op_impl.h"
#include <linux/irq.h>
#include <linux/perf_event.h>
#include <asm/processor.h>
#define PM_CR_BASE 0xff000084 /* 16-bit */
#define PM_CTR_BASE 0xff100004 /* 32-bit */
......@@ -33,15 +28,7 @@
#define PMCR_PMST 0x00004000
#define PMCR_PMEN 0x00008000
struct op_sh_model op_model_sh7750_ops;
#define NR_CNTRS 2
static struct sh7750_ppc_register_config {
unsigned int ctrl;
unsigned long cnt_hi;
unsigned long cnt_lo;
} regcache[NR_CNTRS];
static struct sh_pmu sh7750_pmu;
/*
* There are a number of events supported by each counter (33 in total).
......@@ -85,171 +72,182 @@ static struct sh7750_ppc_register_config {
* 0x27 Pipeline freeze by branch instruction
* 0x28 Pipeline freeze by CPU register
* 0x29 Pipeline freeze by FPU
*
* Unfortunately we don't have a native exception or interrupt for counter
* overflow (although since these counters can run for 16.3 days without
* overflowing, it's not really necessary).
*
* OProfile on the other hand likes to have samples taken periodically, so
* for now we just piggyback the timer interrupt to get the expected
* behavior.
*/
static int sh7750_timer_notify(struct pt_regs *regs)
{
oprofile_add_sample(regs, 0);
return 0;
}
static u64 sh7750_read_counter(int counter)
{
return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) |
__raw_readl(PMCTRL(counter));
}
/*
* Files will be in a path like:
*
* /<oprofilefs mount point>/<counter number>/<file>
*
* So when dealing with <file>, we look to the parent dentry for the counter
* number.
*/
static inline int to_counter(struct file *file)
{
const unsigned char *name = file->f_path.dentry->d_parent->d_name.name;
return (int)simple_strtol(name, NULL, 10);
}
/*
* XXX: We have 48-bit counters, so we're probably going to want something
* more along the lines of oprofilefs_ullong_to_user().. Truncating to
* unsigned long works fine for now though, as long as we don't attempt to
* profile for too horribly long.
*/
static ssize_t sh7750_read_count(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
int counter = to_counter(file);
u64 val = sh7750_read_counter(counter);
static const int sh7750_general_events[] = {
[PERF_COUNT_HW_CPU_CYCLES] = 0x0023,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x000a,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */
[PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010,
[PERF_COUNT_HW_BRANCH_MISSES] = -1,
[PERF_COUNT_HW_BUS_CYCLES] = -1,
};
return oprofilefs_ulong_to_user((unsigned long)val, buf, count, ppos);
}
#define C(x) PERF_COUNT_HW_CACHE_##x
static ssize_t sh7750_write_count(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
static const int sh7750_cache_events
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{
int counter = to_counter(file);
unsigned long val;
if (oprofilefs_ulong_from_user(&val, buf, count))
return -EFAULT;
/*
* Any write will clear the counter, although only 0 should be
* written for this purpose, as we do not support setting the
* counter to an arbitrary value.
*/
WARN_ON(val != 0);
__raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter));
return count;
}
static const struct file_operations count_fops = {
.read = sh7750_read_count,
.write = sh7750_write_count,
[ C(L1D) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0001,
[ C(RESULT_MISS) ] = 0x0004,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0002,
[ C(RESULT_MISS) ] = 0x0005,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(L1I) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0006,
[ C(RESULT_MISS) ] = 0x0008,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(LL) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(DTLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x0003,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(ITLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x0007,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(BPU) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
};
static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir)
static int sh7750_event_map(int event)
{
return oprofilefs_create_file(sb, dir, "count", &count_fops);
return sh7750_general_events[event];
}
static void sh7750_ppc_reg_setup(struct op_counter_config *ctr)
static u64 sh7750_pmu_read(int idx)
{
unsigned int counters = op_model_sh7750_ops.num_counters;
int i;
for (i = 0; i < counters; i++) {
regcache[i].ctrl = 0;
regcache[i].cnt_hi = 0;
regcache[i].cnt_lo = 0;
if (!ctr[i].enabled)
continue;
regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST;
regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff);
regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff);
}
return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) |
__raw_readl(PMCTRL(idx));
}
static void sh7750_ppc_cpu_setup(void *args)
static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx)
{
unsigned int counters = op_model_sh7750_ops.num_counters;
int i;
unsigned int tmp;
for (i = 0; i < counters; i++) {
__raw_writew(0, PMCR(i));
__raw_writel(regcache[i].cnt_hi, PMCTRH(i));
__raw_writel(regcache[i].cnt_lo, PMCTRL(i));
}
tmp = __raw_readw(PMCR(idx));
tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN);
__raw_writew(tmp, PMCR(idx));
}
static void sh7750_ppc_cpu_start(void *args)
static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx)
{
unsigned int counters = op_model_sh7750_ops.num_counters;
int i;
for (i = 0; i < counters; i++)
__raw_writew(regcache[i].ctrl, PMCR(i));
__raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx));
__raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx));
}
static void sh7750_ppc_cpu_stop(void *args)
static void sh7750_pmu_disable_all(void)
{
unsigned int counters = op_model_sh7750_ops.num_counters;
int i;
/* Disable the counters */
for (i = 0; i < counters; i++)
for (i = 0; i < sh7750_pmu.num_events; i++)
__raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i));
}
static inline void sh7750_ppc_reset(void)
static void sh7750_pmu_enable_all(void)
{
unsigned int counters = op_model_sh7750_ops.num_counters;
int i;
/* Clear the counters */
for (i = 0; i < counters; i++)
__raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i));
for (i = 0; i < sh7750_pmu.num_events; i++)
__raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i));
}
static int sh7750_ppc_init(void)
{
sh7750_ppc_reset();
return register_timer_hook(sh7750_timer_notify);
}
static struct sh_pmu sh7750_pmu = {
.name = "SH7750",
.num_events = 2,
.event_map = sh7750_event_map,
.max_events = ARRAY_SIZE(sh7750_general_events),
.raw_event_mask = PMCR_PMM_MASK,
.cache_events = &sh7750_cache_events,
.read = sh7750_pmu_read,
.disable = sh7750_pmu_disable,
.enable = sh7750_pmu_enable,
.disable_all = sh7750_pmu_disable_all,
.enable_all = sh7750_pmu_enable_all,
};
static void sh7750_ppc_exit(void)
static int __init sh7750_pmu_init(void)
{
unregister_timer_hook(sh7750_timer_notify);
/*
* Make sure this CPU actually has perf counters.
*/
if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
pr_notice("HW perf events unsupported, software events only.\n");
return -ENODEV;
}
sh7750_ppc_reset();
return register_sh_pmu(&sh7750_pmu);
}
struct op_sh_model op_model_sh7750_ops = {
.cpu_type = "sh/sh7750",
.num_counters = NR_CNTRS,
.reg_setup = sh7750_ppc_reg_setup,
.cpu_setup = sh7750_ppc_cpu_setup,
.cpu_start = sh7750_ppc_cpu_start,
.cpu_stop = sh7750_ppc_cpu_stop,
.init = sh7750_ppc_init,
.exit = sh7750_ppc_exit,
.create_files = sh7750_ppc_create_files,
};
arch_initcall(sh7750_pmu_init);
......@@ -44,3 +44,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o
obj-y += $(clock-y)
obj-$(CONFIG_SMP) += $(smp-y)
obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y)
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
......@@ -152,7 +152,7 @@ struct clk div6_clks[] = {
SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0),
SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0),
SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0),
SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0),
SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT),
};
#define R_CLK (&r_clk)
......
/*
* Performance events support for SH-4A performance counters
*
* Copyright (C) 2009 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/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/perf_event.h>
#include <asm/processor.h>
#define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx))
#define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx))
#define CCBR_CIT_MASK (0x7ff << 6)
#define CCBR_DUC (1 << 3)
#define CCBR_CMDS (1 << 1)
#define CCBR_PPCE (1 << 0)
#define PPC_PMCAT 0xfc100080
#define PMCAT_OVF3 (1 << 27)
#define PMCAT_CNN3 (1 << 26)
#define PMCAT_CLR3 (1 << 25)
#define PMCAT_OVF2 (1 << 19)
#define PMCAT_CLR2 (1 << 17)
#define PMCAT_OVF1 (1 << 11)
#define PMCAT_CNN1 (1 << 10)
#define PMCAT_CLR1 (1 << 9)
#define PMCAT_OVF0 (1 << 3)
#define PMCAT_CLR0 (1 << 1)
static struct sh_pmu sh4a_pmu;
/*
* Supported raw event codes:
*
* Event Code Description
* ---------- -----------
*
* 0x0000 number of elapsed cycles
* 0x0200 number of elapsed cycles in privileged mode
* 0x0280 number of elapsed cycles while SR.BL is asserted
* 0x0202 instruction execution
* 0x0203 instruction execution in parallel
* 0x0204 number of unconditional branches
* 0x0208 number of exceptions
* 0x0209 number of interrupts
* 0x0220 UTLB miss caused by instruction fetch
* 0x0222 UTLB miss caused by operand access
* 0x02a0 number of ITLB misses
* 0x0028 number of accesses to instruction memories
* 0x0029 number of accesses to instruction cache
* 0x002a instruction cache miss
* 0x022e number of access to instruction X/Y memory
* 0x0030 number of reads to operand memories
* 0x0038 number of writes to operand memories
* 0x0031 number of operand cache read accesses
* 0x0039 number of operand cache write accesses
* 0x0032 operand cache read miss
* 0x003a operand cache write miss
* 0x0236 number of reads to operand X/Y memory
* 0x023e number of writes to operand X/Y memory
* 0x0237 number of reads to operand U memory
* 0x023f number of writes to operand U memory
* 0x0337 number of U memory read buffer misses
* 0x02b4 number of wait cycles due to operand read access
* 0x02bc number of wait cycles due to operand write access
* 0x0033 number of wait cycles due to operand cache read miss
* 0x003b number of wait cycles due to operand cache write miss
*/
/*
* Special reserved bits used by hardware emulators, read values will
* vary, but writes must always be 0.
*/
#define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0))
static const int sh4a_general_events[] = {
[PERF_COUNT_HW_CPU_CYCLES] = 0x0000,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x0202,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */
[PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204,
[PERF_COUNT_HW_BRANCH_MISSES] = -1,
[PERF_COUNT_HW_BUS_CYCLES] = -1,
};
#define C(x) PERF_COUNT_HW_CACHE_##x
static const int sh4a_cache_events
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{
[ C(L1D) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0031,
[ C(RESULT_MISS) ] = 0x0032,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0039,
[ C(RESULT_MISS) ] = 0x003a,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(L1I) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0029,
[ C(RESULT_MISS) ] = 0x002a,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(LL) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0030,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0x0038,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(DTLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0x0222,
[ C(RESULT_MISS) ] = 0x0220,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
},
[ C(ITLB) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0x02a0,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
[ C(BPU) ] = {
[ C(OP_READ) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_WRITE) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
[ C(OP_PREFETCH) ] = {
[ C(RESULT_ACCESS) ] = -1,
[ C(RESULT_MISS) ] = -1,
},
},
};
static int sh4a_event_map(int event)
{
return sh4a_general_events[event];
}
static u64 sh4a_pmu_read(int idx)
{
return __raw_readl(PPC_PMCTR(idx));
}
static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx)
{
unsigned int tmp;
tmp = __raw_readl(PPC_CCBR(idx));
tmp &= ~(CCBR_CIT_MASK | CCBR_DUC);
__raw_writel(tmp, PPC_CCBR(idx));
}
static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx)
{
unsigned int tmp;
tmp = __raw_readl(PPC_PMCAT);
tmp &= ~PMCAT_EMU_CLR_MASK;
tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0;
__raw_writel(tmp, PPC_PMCAT);
tmp = __raw_readl(PPC_CCBR(idx));
tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE;
__raw_writel(tmp, PPC_CCBR(idx));
__raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx));
}
static void sh4a_pmu_disable_all(void)
{
int i;
for (i = 0; i < sh4a_pmu.num_events; i++)
__raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i));
}
static void sh4a_pmu_enable_all(void)
{
int i;
for (i = 0; i < sh4a_pmu.num_events; i++)
__raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i));
}
static struct sh_pmu sh4a_pmu = {
.name = "SH-4A",
.num_events = 2,
.event_map = sh4a_event_map,
.max_events = ARRAY_SIZE(sh4a_general_events),
.raw_event_mask = 0x3ff,
.cache_events = &sh4a_cache_events,
.read = sh4a_pmu_read,
.disable = sh4a_pmu_disable,
.enable = sh4a_pmu_enable,
.disable_all = sh4a_pmu_disable_all,
.enable_all = sh4a_pmu_enable_all,
};
static int __init sh4a_pmu_init(void)
{
/*
* Make sure this CPU actually has perf counters.
*/
if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) {
pr_notice("HW perf events unsupported, software events only.\n");
return -ENODEV;
}
return register_sh_pmu(&sh4a_pmu);
}
arch_initcall(sh4a_pmu_init);
......@@ -20,6 +20,8 @@
#include <linux/uio_driver.h>
#include <linux/sh_timer.h>
#include <linux/io.h>
#include <linux/notifier.h>
#include <asm/suspend.h>
#include <asm/clock.h>
#include <asm/mmzone.h>
#include <cpu/sh7724.h>
......@@ -523,6 +525,70 @@ static struct platform_device jpu_device = {
},
};
/* SPU2DSP0 */
static struct uio_info spu0_platform_data = {
.name = "SPU2DSP0",
.version = "0",
.irq = 86,
};
static struct resource spu0_resources[] = {
[0] = {
.name = "SPU2DSP0",
.start = 0xFE200000,
.end = 0xFE2FFFFF,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device spu0_device = {
.name = "uio_pdrv_genirq",
.id = 4,
.dev = {
.platform_data = &spu0_platform_data,
},
.resource = spu0_resources,
.num_resources = ARRAY_SIZE(spu0_resources),
.archdata = {
.hwblk_id = HWBLK_SPU,
},
};
/* SPU2DSP1 */
static struct uio_info spu1_platform_data = {
.name = "SPU2DSP1",
.version = "0",
.irq = 87,
};
static struct resource spu1_resources[] = {
[0] = {
.name = "SPU2DSP1",
.start = 0xFE300000,
.end = 0xFE3FFFFF,
.flags = IORESOURCE_MEM,
},
[1] = {
/* place holder for contiguous memory */
},
};
static struct platform_device spu1_device = {
.name = "uio_pdrv_genirq",
.id = 5,
.dev = {
.platform_data = &spu1_platform_data,
},
.resource = spu1_resources,
.num_resources = ARRAY_SIZE(spu1_resources),
.archdata = {
.hwblk_id = HWBLK_SPU,
},
};
static struct platform_device *sh7724_devices[] __initdata = {
&cmt_device,
&tmu0_device,
......@@ -539,6 +605,8 @@ static struct platform_device *sh7724_devices[] __initdata = {
&veu0_device,
&veu1_device,
&jpu_device,
&spu0_device,
&spu1_device,
};
static int __init sh7724_devices_setup(void)
......@@ -547,6 +615,8 @@ static int __init sh7724_devices_setup(void)
platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20);
platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20);
platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20);
platform_resource_setup_memory(&spu0_device, "spu0", 2 << 20);
platform_resource_setup_memory(&spu1_device, "spu1", 2 << 20);
return platform_add_devices(sh7724_devices,
ARRAY_SIZE(sh7724_devices));
......@@ -827,3 +897,182 @@ void __init plat_irq_setup(void)
{
register_intc_controller(&intc_desc);
}
static struct {
/* BSC */
unsigned long mmselr;
unsigned long cs0bcr;
unsigned long cs4bcr;
unsigned long cs5abcr;
unsigned long cs5bbcr;
unsigned long cs6abcr;
unsigned long cs6bbcr;
unsigned long cs4wcr;
unsigned long cs5awcr;
unsigned long cs5bwcr;
unsigned long cs6awcr;
unsigned long cs6bwcr;
/* INTC */
unsigned short ipra;
unsigned short iprb;
unsigned short iprc;
unsigned short iprd;
unsigned short ipre;
unsigned short iprf;
unsigned short iprg;
unsigned short iprh;
unsigned short ipri;
unsigned short iprj;
unsigned short iprk;
unsigned short iprl;
unsigned char imr0;
unsigned char imr1;
unsigned char imr2;
unsigned char imr3;
unsigned char imr4;
unsigned char imr5;
unsigned char imr6;
unsigned char imr7;
unsigned char imr8;
unsigned char imr9;
unsigned char imr10;
unsigned char imr11;
unsigned char imr12;
/* RWDT */
unsigned short rwtcnt;
unsigned short rwtcsr;
} sh7724_rstandby_state;
static int sh7724_pre_sleep_notifier_call(struct notifier_block *nb,
unsigned long flags, void *unused)
{
if (!(flags & SUSP_SH_RSTANDBY))
return NOTIFY_DONE;
/* BCR */
sh7724_rstandby_state.mmselr = __raw_readl(0xff800020); /* MMSELR */
sh7724_rstandby_state.mmselr |= 0xa5a50000;
sh7724_rstandby_state.cs0bcr = __raw_readl(0xfec10004); /* CS0BCR */
sh7724_rstandby_state.cs4bcr = __raw_readl(0xfec10010); /* CS4BCR */
sh7724_rstandby_state.cs5abcr = __raw_readl(0xfec10014); /* CS5ABCR */
sh7724_rstandby_state.cs5bbcr = __raw_readl(0xfec10018); /* CS5BBCR */
sh7724_rstandby_state.cs6abcr = __raw_readl(0xfec1001c); /* CS6ABCR */
sh7724_rstandby_state.cs6bbcr = __raw_readl(0xfec10020); /* CS6BBCR */
sh7724_rstandby_state.cs4wcr = __raw_readl(0xfec10030); /* CS4WCR */
sh7724_rstandby_state.cs5awcr = __raw_readl(0xfec10034); /* CS5AWCR */
sh7724_rstandby_state.cs5bwcr = __raw_readl(0xfec10038); /* CS5BWCR */
sh7724_rstandby_state.cs6awcr = __raw_readl(0xfec1003c); /* CS6AWCR */
sh7724_rstandby_state.cs6bwcr = __raw_readl(0xfec10040); /* CS6BWCR */
/* INTC */
sh7724_rstandby_state.ipra = __raw_readw(0xa4080000); /* IPRA */
sh7724_rstandby_state.iprb = __raw_readw(0xa4080004); /* IPRB */
sh7724_rstandby_state.iprc = __raw_readw(0xa4080008); /* IPRC */
sh7724_rstandby_state.iprd = __raw_readw(0xa408000c); /* IPRD */
sh7724_rstandby_state.ipre = __raw_readw(0xa4080010); /* IPRE */
sh7724_rstandby_state.iprf = __raw_readw(0xa4080014); /* IPRF */
sh7724_rstandby_state.iprg = __raw_readw(0xa4080018); /* IPRG */
sh7724_rstandby_state.iprh = __raw_readw(0xa408001c); /* IPRH */
sh7724_rstandby_state.ipri = __raw_readw(0xa4080020); /* IPRI */
sh7724_rstandby_state.iprj = __raw_readw(0xa4080024); /* IPRJ */
sh7724_rstandby_state.iprk = __raw_readw(0xa4080028); /* IPRK */
sh7724_rstandby_state.iprl = __raw_readw(0xa408002c); /* IPRL */
sh7724_rstandby_state.imr0 = __raw_readb(0xa4080080); /* IMR0 */
sh7724_rstandby_state.imr1 = __raw_readb(0xa4080084); /* IMR1 */
sh7724_rstandby_state.imr2 = __raw_readb(0xa4080088); /* IMR2 */
sh7724_rstandby_state.imr3 = __raw_readb(0xa408008c); /* IMR3 */
sh7724_rstandby_state.imr4 = __raw_readb(0xa4080090); /* IMR4 */
sh7724_rstandby_state.imr5 = __raw_readb(0xa4080094); /* IMR5 */
sh7724_rstandby_state.imr6 = __raw_readb(0xa4080098); /* IMR6 */
sh7724_rstandby_state.imr7 = __raw_readb(0xa408009c); /* IMR7 */
sh7724_rstandby_state.imr8 = __raw_readb(0xa40800a0); /* IMR8 */
sh7724_rstandby_state.imr9 = __raw_readb(0xa40800a4); /* IMR9 */
sh7724_rstandby_state.imr10 = __raw_readb(0xa40800a8); /* IMR10 */
sh7724_rstandby_state.imr11 = __raw_readb(0xa40800ac); /* IMR11 */
sh7724_rstandby_state.imr12 = __raw_readb(0xa40800b0); /* IMR12 */
/* RWDT */
sh7724_rstandby_state.rwtcnt = __raw_readb(0xa4520000); /* RWTCNT */
sh7724_rstandby_state.rwtcnt |= 0x5a00;
sh7724_rstandby_state.rwtcsr = __raw_readb(0xa4520004); /* RWTCSR */
sh7724_rstandby_state.rwtcsr |= 0xa500;
__raw_writew(sh7724_rstandby_state.rwtcsr & 0x07, 0xa4520004);
return NOTIFY_DONE;
}
static int sh7724_post_sleep_notifier_call(struct notifier_block *nb,
unsigned long flags, void *unused)
{
if (!(flags & SUSP_SH_RSTANDBY))
return NOTIFY_DONE;
/* BCR */
__raw_writel(sh7724_rstandby_state.mmselr, 0xff800020); /* MMSELR */
__raw_writel(sh7724_rstandby_state.cs0bcr, 0xfec10004); /* CS0BCR */
__raw_writel(sh7724_rstandby_state.cs4bcr, 0xfec10010); /* CS4BCR */
__raw_writel(sh7724_rstandby_state.cs5abcr, 0xfec10014); /* CS5ABCR */
__raw_writel(sh7724_rstandby_state.cs5bbcr, 0xfec10018); /* CS5BBCR */
__raw_writel(sh7724_rstandby_state.cs6abcr, 0xfec1001c); /* CS6ABCR */
__raw_writel(sh7724_rstandby_state.cs6bbcr, 0xfec10020); /* CS6BBCR */
__raw_writel(sh7724_rstandby_state.cs4wcr, 0xfec10030); /* CS4WCR */
__raw_writel(sh7724_rstandby_state.cs5awcr, 0xfec10034); /* CS5AWCR */
__raw_writel(sh7724_rstandby_state.cs5bwcr, 0xfec10038); /* CS5BWCR */
__raw_writel(sh7724_rstandby_state.cs6awcr, 0xfec1003c); /* CS6AWCR */
__raw_writel(sh7724_rstandby_state.cs6bwcr, 0xfec10040); /* CS6BWCR */
/* INTC */
__raw_writew(sh7724_rstandby_state.ipra, 0xa4080000); /* IPRA */
__raw_writew(sh7724_rstandby_state.iprb, 0xa4080004); /* IPRB */
__raw_writew(sh7724_rstandby_state.iprc, 0xa4080008); /* IPRC */
__raw_writew(sh7724_rstandby_state.iprd, 0xa408000c); /* IPRD */
__raw_writew(sh7724_rstandby_state.ipre, 0xa4080010); /* IPRE */
__raw_writew(sh7724_rstandby_state.iprf, 0xa4080014); /* IPRF */
__raw_writew(sh7724_rstandby_state.iprg, 0xa4080018); /* IPRG */
__raw_writew(sh7724_rstandby_state.iprh, 0xa408001c); /* IPRH */
__raw_writew(sh7724_rstandby_state.ipri, 0xa4080020); /* IPRI */
__raw_writew(sh7724_rstandby_state.iprj, 0xa4080024); /* IPRJ */
__raw_writew(sh7724_rstandby_state.iprk, 0xa4080028); /* IPRK */
__raw_writew(sh7724_rstandby_state.iprl, 0xa408002c); /* IPRL */
__raw_writeb(sh7724_rstandby_state.imr0, 0xa4080080); /* IMR0 */
__raw_writeb(sh7724_rstandby_state.imr1, 0xa4080084); /* IMR1 */
__raw_writeb(sh7724_rstandby_state.imr2, 0xa4080088); /* IMR2 */
__raw_writeb(sh7724_rstandby_state.imr3, 0xa408008c); /* IMR3 */
__raw_writeb(sh7724_rstandby_state.imr4, 0xa4080090); /* IMR4 */
__raw_writeb(sh7724_rstandby_state.imr5, 0xa4080094); /* IMR5 */
__raw_writeb(sh7724_rstandby_state.imr6, 0xa4080098); /* IMR6 */
__raw_writeb(sh7724_rstandby_state.imr7, 0xa408009c); /* IMR7 */
__raw_writeb(sh7724_rstandby_state.imr8, 0xa40800a0); /* IMR8 */
__raw_writeb(sh7724_rstandby_state.imr9, 0xa40800a4); /* IMR9 */
__raw_writeb(sh7724_rstandby_state.imr10, 0xa40800a8); /* IMR10 */
__raw_writeb(sh7724_rstandby_state.imr11, 0xa40800ac); /* IMR11 */
__raw_writeb(sh7724_rstandby_state.imr12, 0xa40800b0); /* IMR12 */
/* RWDT */
__raw_writew(sh7724_rstandby_state.rwtcnt, 0xa4520000); /* RWTCNT */
__raw_writew(sh7724_rstandby_state.rwtcsr, 0xa4520004); /* RWTCSR */
return NOTIFY_DONE;
}
static struct notifier_block sh7724_pre_sleep_notifier = {
.notifier_call = sh7724_pre_sleep_notifier_call,
.priority = SH_MOBILE_PRE(SH_MOBILE_SLEEP_CPU),
};
static struct notifier_block sh7724_post_sleep_notifier = {
.notifier_call = sh7724_post_sleep_notifier_call,
.priority = SH_MOBILE_POST(SH_MOBILE_SLEEP_CPU),
};
static int __init sh7724_sleep_setup(void)
{
atomic_notifier_chain_register(&sh_mobile_pre_sleep_notifier_list,
&sh7724_pre_sleep_notifier);
atomic_notifier_chain_register(&sh_mobile_post_sleep_notifier_list,
&sh7724_post_sleep_notifier);
return 0;
}
arch_initcall(sh7724_sleep_setup);
......@@ -15,6 +15,15 @@
#include <linux/sh_timer.h>
#include <asm/mmzone.h>
/*
* This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2
* INTEVT values overlap with the FPU EXPEVT ones, requiring special
* demuxing in the exception dispatch path.
*
* As this overlap is something that never should have made it in to
* silicon in the first place, we just refuse to deal with the port at
* all rather than adding infrastructure to hack around it.
*/
static struct plat_sci_port sci_platform_data[] = {
{
.mapbase = 0xffc30000,
......@@ -26,11 +35,6 @@ static struct plat_sci_port sci_platform_data[] = {
.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,
......@@ -268,7 +272,11 @@ enum {
UNUSED = 0,
/* interrupt sources */
IRL, IRQ0, IRQ1, IRQ2, IRQ3,
IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
IRL_HHLL, IRL_HHLH, IRL_HHHL,
IRQ0, IRQ1, IRQ2, IRQ3,
HUDII,
TMU0, TMU1, TMU2, TMU3, TMU4, TMU5,
PCII0, PCII1, PCII2, PCII3, PCII4,
......@@ -291,7 +299,7 @@ enum {
INTICI4, INTICI5, INTICI6, INTICI7,
/* interrupt groups */
PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
DMAC0, DMAC1,
};
......@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = {
INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760),
INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0),
INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0),
INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820),
INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860),
INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0),
INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0),
INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920),
......@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = {
};
static struct intc_group groups[] __initdata = {
INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH,
IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH,
IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH,
IRL_HHLL, IRL_HHLH, IRL_HHHL),
INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9),
INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI),
INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI),
INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI),
INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI),
INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2,
DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE),
......@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups,
/* External interrupt pins in IRL mode */
static struct intc_vect vectors_irl[] __initdata = {
INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220),
INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260),
INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0),
INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0),
INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320),
INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360),
INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0),
INTC_VECT(IRL, 0x3c0),
INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220),
INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260),
INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0),
INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0),
INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320),
INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360),
INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0),
INTC_VECT(IRL_HHHL, 0x3c0),
};
static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups,
......
......@@ -14,6 +14,13 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
#define STBCR_MSTP 0x00000001
#define STBCR_RESET 0x00000002
#define STBCR_LTSLP 0x80000000
static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
{
unsigned int message = (unsigned int)(long)arg;
......@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg)
unsigned int offs = 4 * cpu;
unsigned int x;
x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */
x &= (1 << (message << 2));
ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
__raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */
smp_message_recv(message);
......@@ -37,6 +44,9 @@ void __init plat_smp_setup(void)
init_cpu_possible(cpumask_of(cpu));
/* Enable light sleep for the boot CPU */
__raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu));
__cpu_number_map[0] = 0;
__cpu_logical_map[0] = 0;
......@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
"IPI", (void *)(long)i);
}
#define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12))
#define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12))
#define STBCR_MSTP 0x00000001
#define STBCR_RESET 0x00000002
#define STBCR_LTSLP 0x80000000
#define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP)
void plat_start_cpu(unsigned int cpu, unsigned long entry_point)
{
ctrl_outl(entry_point, RESET_REG(cpu));
__raw_writel(entry_point, RESET_REG(cpu));
if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
ctrl_outl(STBCR_MSTP, STBCR_REG(cpu));
if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
__raw_writel(STBCR_MSTP, STBCR_REG(cpu));
while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP))
while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP))
cpu_relax();
/* Start up secondary processor by sending a reset */
ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu));
__raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu));
}
int plat_smp_processor_id(void)
{
return ctrl_inl(0xff000048); /* CPIDR */
return __raw_readl(0xff000048); /* CPIDR */
}
void plat_send_ipi(unsigned int cpu, unsigned int message)
......@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message)
BUG_ON(cpu >= 4);
ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
__raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */
}
......@@ -933,7 +933,7 @@ ret_with_reschedule:
pta restore_all, tr1
movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8
movi _TIF_SIGPENDING, r8
and r8, r7, r8
pta work_notifysig, tr0
bne r8, ZERO, tr0
......
......@@ -87,25 +87,31 @@ void sh_mobile_setup_cpuidle(void)
dev->safe_state = state;
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN);
state->exit_latency = 100;
state->target_residency = 1 * 2;
state->power_usage = 1;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
if (sh_mobile_sleep_supported & SUSP_SH_SF) {
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C1");
strncpy(state->desc, "SuperH Sleep Mode [SF]",
CPUIDLE_DESC_LEN);
state->exit_latency = 100;
state->target_residency = 1 * 2;
state->power_usage = 1;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
}
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN);
state->exit_latency = 2300;
state->target_residency = 1 * 2;
state->power_usage = 1;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) {
state = &dev->states[i++];
snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
strncpy(state->desc, "SuperH Mobile Standby Mode [SF]",
CPUIDLE_DESC_LEN);
state->exit_latency = 2300;
state->target_residency = 1 * 2;
state->power_usage = 1;
state->flags = 0;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = cpuidle_sleep_enter;
}
dev->state_count = i;
......
......@@ -15,6 +15,13 @@
#include <linux/suspend.h>
#include <asm/suspend.h>
#include <asm/uaccess.h>
#include <asm/cacheflush.h>
/*
* Notifier lists for pre/post sleep notification
*/
ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list);
ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list);
/*
* Sleep modes available on SuperH Mobile:
......@@ -26,30 +33,105 @@
#define SUSP_MODE_SLEEP (SUSP_SH_SLEEP)
#define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF)
#define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF)
#define SUSP_MODE_RSTANDBY (SUSP_SH_RSTANDBY | SUSP_SH_MMU | SUSP_SH_SF)
/*
* U-standby mode is unsupported since it needs bootloader hacks
*/
/*
* The following modes are not there yet:
*
* R-standby mode is unsupported, but will be added in the future
* U-standby mode is low priority since it needs bootloader hacks
*/
#define ILRAM_BASE 0xe5200000
extern const unsigned char sh_mobile_standby[];
extern const unsigned int sh_mobile_standby_size;
#ifdef CONFIG_CPU_SUBTYPE_SH7724
#define RAM_BASE 0xfd800000 /* RSMEM */
#else
#define RAM_BASE 0xe5200000 /* ILRAM */
#endif
void sh_mobile_call_standby(unsigned long mode)
{
void *onchip_mem = (void *)ILRAM_BASE;
void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem;
void *onchip_mem = (void *)RAM_BASE;
struct sh_sleep_data *sdp = onchip_mem;
void (*standby_onchip_mem)(unsigned long, unsigned long);
/* code located directly after data structure */
standby_onchip_mem = (void *)(sdp + 1);
atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list,
mode, NULL);
/* flush the caches if MMU flag is set */
if (mode & SUSP_SH_MMU)
flush_cache_all();
/* Let assembly snippet in on-chip memory handle the rest */
standby_onchip_mem(mode, ILRAM_BASE);
standby_onchip_mem(mode, RAM_BASE);
atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list,
mode, NULL);
}
extern char sh_mobile_sleep_enter_start;
extern char sh_mobile_sleep_enter_end;
extern char sh_mobile_sleep_resume_start;
extern char sh_mobile_sleep_resume_end;
unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP;
void sh_mobile_register_self_refresh(unsigned long flags,
void *pre_start, void *pre_end,
void *post_start, void *post_end)
{
void *onchip_mem = (void *)RAM_BASE;
void *vp;
struct sh_sleep_data *sdp;
int n;
/* part 0: data area */
sdp = onchip_mem;
sdp->addr.stbcr = 0xa4150020; /* STBCR */
sdp->addr.bar = 0xa4150040; /* BAR */
sdp->addr.pteh = 0xff000000; /* PTEH */
sdp->addr.ptel = 0xff000004; /* PTEL */
sdp->addr.ttb = 0xff000008; /* TTB */
sdp->addr.tea = 0xff00000c; /* TEA */
sdp->addr.mmucr = 0xff000010; /* MMUCR */
sdp->addr.ptea = 0xff000034; /* PTEA */
sdp->addr.pascr = 0xff000070; /* PASCR */
sdp->addr.irmcr = 0xff000078; /* IRMCR */
sdp->addr.ccr = 0xff00001c; /* CCR */
sdp->addr.ramcr = 0xff000074; /* RAMCR */
vp = sdp + 1;
/* part 1: common code to enter sleep mode */
n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start;
memcpy(vp, &sh_mobile_sleep_enter_start, n);
vp += roundup(n, 4);
/* part 2: board specific code to enter self-refresh mode */
n = pre_end - pre_start;
memcpy(vp, pre_start, n);
sdp->sf_pre = (unsigned long)vp;
vp += roundup(n, 4);
/* part 3: board specific code to resume from self-refresh mode */
n = post_end - post_start;
memcpy(vp, post_start, n);
sdp->sf_post = (unsigned long)vp;
vp += roundup(n, 4);
/* part 4: common code to resume from sleep mode */
WARN_ON(vp > (onchip_mem + 0x600));
vp = onchip_mem + 0x600; /* located at interrupt vector */
n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start;
memcpy(vp, &sh_mobile_sleep_resume_start, n);
sdp->resume = (unsigned long)vp;
sh_mobile_sleep_supported |= flags;
}
static int sh_pm_enter(suspend_state_t state)
{
if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF))
return -ENXIO;
local_irq_disable();
set_bl_bit();
sh_mobile_call_standby(SUSP_MODE_STANDBY_SF);
......@@ -65,13 +147,6 @@ static struct platform_suspend_ops sh_pm_ops = {
static int __init sh_pm_init(void)
{
void *onchip_mem = (void *)ILRAM_BASE;
/* Copy the assembly snippet to the otherwise ununsed ILRAM */
memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size);
wmb();
ctrl_barrier();
suspend_set_ops(&sh_pm_ops);
sh_mobile_setup_cpuidle();
return 0;
......
......@@ -20,79 +20,103 @@
* Kernel mode register usage, see entry.S:
* k0 scratch
* k1 scratch
* k4 scratch
*/
#define k0 r0
#define k1 r1
#define k4 r4
/* manage self-refresh and enter standby mode.
/* manage self-refresh and enter standby mode. must be self-contained.
* this code will be copied to on-chip memory and executed from there.
*/
.balign 4
ENTRY(sh_mobile_sleep_enter_start)
.balign 4096,0,4096
ENTRY(sh_mobile_standby)
/* save mode flags */
mov.l r4, @(SH_SLEEP_MODE, r5)
/* save original vbr */
stc vbr, r1
mova saved_vbr, r0
mov.l r1, @r0
stc vbr, r0
mov.l r0, @(SH_SLEEP_VBR, r5)
/* point vbr to our on-chip memory page */
ldc r5, vbr
/* save return address */
mova saved_spc, r0
sts pr, r5
mov.l r5, @r0
sts pr, r0
mov.l r0, @(SH_SLEEP_SPC, r5)
/* save sr */
mova saved_sr, r0
stc sr, r5
mov.l r5, @r0
stc sr, r0
mov.l r0, @(SH_SLEEP_SR, r5)
/* save mode flags */
mova saved_mode, r0
mov.l r4, @r0
/* save sp */
mov.l r15, @(SH_SLEEP_SP, r5)
/* save stbcr */
bsr save_register
mov #SH_SLEEP_REG_STBCR, r0
/* save mmu and cache context if needed */
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_MMU, r0
bt skip_mmu_save_disable
/* save mmu state */
bsr save_register
mov #SH_SLEEP_REG_PTEH, r0
bsr save_register
mov #SH_SLEEP_REG_PTEL, r0
bsr save_register
mov #SH_SLEEP_REG_TTB, r0
bsr save_register
mov #SH_SLEEP_REG_TEA, r0
bsr save_register
mov #SH_SLEEP_REG_MMUCR, r0
bsr save_register
mov #SH_SLEEP_REG_PTEA, r0
bsr save_register
mov #SH_SLEEP_REG_PASCR, r0
/* put mode flags in r0 */
mov r4, r0
bsr save_register
mov #SH_SLEEP_REG_IRMCR, r0
/* invalidate TLBs and disable the MMU */
bsr get_register
mov #SH_SLEEP_REG_MMUCR, r0
mov #4, r1
mov.l r1, @r0
icbi @r0
/* save cache registers and disable caches */
bsr save_register
mov #SH_SLEEP_REG_CCR, r0
bsr save_register
mov #SH_SLEEP_REG_RAMCR, r0
bsr get_register
mov #SH_SLEEP_REG_CCR, r0
mov #0, r1
mov.l r1, @r0
icbi @r0
skip_mmu_save_disable:
/* call self-refresh entering code if needed */
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_SF, r0
bt skip_set_sf
#ifdef CONFIG_CPU_SUBTYPE_SH7724
/* DBSC: put memory in self-refresh mode */
mov.l dben_reg, r4
mov.l dben_data0, r1
mov.l r1, @r4
mov.l dbrfpdn0_reg, r4
mov.l dbrfpdn0_data0, r1
mov.l r1, @r4
mov.l dbcmdcnt_reg, r4
mov.l dbcmdcnt_data0, r1
mov.l r1, @r4
mov.l dbcmdcnt_reg, r4
mov.l dbcmdcnt_data1, r1
mov.l r1, @r4
mov.l dbrfpdn0_reg, r4
mov.l dbrfpdn0_data1, r1
mov.l r1, @r4
#else
/* SBSC: disable power down and put in self-refresh mode */
mov.l 1f, r4
mov.l 2f, r1
mov.l @r4, r2
or r1, r2
mov.l 3f, r3
and r3, r2
mov.l r2, @r4
#endif
mov.l @(SH_SLEEP_SF_PRE, r5), r0
jsr @r0
nop
skip_set_sf:
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_STANDBY, r0
bt test_rstandby
......@@ -104,6 +128,12 @@ test_rstandby:
tst #SUSP_SH_RSTANDBY, r0
bt test_ustandby
/* setup BAR register */
bsr get_register
mov #SH_SLEEP_REG_BAR, r0
mov.l @(SH_SLEEP_RESUME, r5), r1
mov.l r1, @r0
/* set mode to "r-standby mode" */
bra do_sleep
mov #0x20, r1
......@@ -123,124 +153,136 @@ force_sleep:
do_sleep:
/* setup and enter selected standby mode */
mov.l 5f, r4
mov.l r1, @r4
bsr get_register
mov #SH_SLEEP_REG_STBCR, r0
mov.l r1, @r0
again:
sleep
bra again
nop
restore_jump_vbr:
save_register:
add #SH_SLEEP_BASE_ADDR, r0
mov.l @(r0, r5), r1
add #-SH_SLEEP_BASE_ADDR, r0
mov.l @r1, r1
add #SH_SLEEP_BASE_DATA, r0
mov.l r1, @(r0, r5)
add #-SH_SLEEP_BASE_DATA, r0
rts
nop
get_register:
add #SH_SLEEP_BASE_ADDR, r0
mov.l @(r0, r5), r0
rts
nop
ENTRY(sh_mobile_sleep_enter_end)
.balign 4
ENTRY(sh_mobile_sleep_resume_start)
/* figure out start address */
bsr 0f
nop
0:
sts pr, k1
mov.l 1f, k0
and k0, k1
/* store pointer to data area in VBR */
ldc k1, vbr
/* setup sr with saved sr */
mov.l @(SH_SLEEP_SR, k1), k0
ldc k0, sr
/* now: user register set! */
stc vbr, r5
/* setup spc with return address to c code */
mov.l saved_spc, k0
ldc k0, spc
mov.l @(SH_SLEEP_SPC, r5), r0
ldc r0, spc
/* restore vbr */
mov.l saved_vbr, k0
ldc k0, vbr
mov.l @(SH_SLEEP_VBR, r5), r0
ldc r0, vbr
/* setup ssr with saved sr */
mov.l saved_sr, k0
ldc k0, ssr
mov.l @(SH_SLEEP_SR, r5), r0
ldc r0, ssr
/* get mode flags */
mov.l saved_mode, k0
/* restore sp */
mov.l @(SH_SLEEP_SP, r5), r15
done_sleep:
/* reset standby mode to sleep mode */
mov.l 5f, k4
mov #0x00, k1
mov.l k1, @k4
/* restore sleep mode register */
bsr restore_register
mov #SH_SLEEP_REG_STBCR, r0
tst #SUSP_SH_SF, k0
/* call self-refresh resume code if needed */
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_SF, r0
bt skip_restore_sf
#ifdef CONFIG_CPU_SUBTYPE_SH7724
/* DBSC: put memory in auto-refresh mode */
mov.l dbrfpdn0_reg, k4
mov.l dbrfpdn0_data0, k1
mov.l k1, @k4
nop /* sleep 140 ns */
nop
nop
nop
mov.l dbcmdcnt_reg, k4
mov.l dbcmdcnt_data0, k1
mov.l k1, @k4
mov.l dbcmdcnt_reg, k4
mov.l dbcmdcnt_data1, k1
mov.l k1, @k4
mov.l dben_reg, k4
mov.l dben_data1, k1
mov.l k1, @k4
mov.l dbrfpdn0_reg, k4
mov.l dbrfpdn0_data2, k1
mov.l k1, @k4
#else
/* SBSC: set auto-refresh mode */
mov.l 1f, k4
mov.l @k4, k0
mov.l 4f, k1
and k1, k0
mov.l k0, @k4
mov.l 6f, k4
mov.l 8f, k0
mov.l @k4, k1
mov #-1, k4
add k4, k1
or k1, k0
mov.l 7f, k1
mov.l k0, @k1
#endif
mov.l @(SH_SLEEP_SF_POST, r5), r0
jsr @r0
nop
skip_restore_sf:
/* jump to vbr vector */
mov.l saved_vbr, k0
mov.l offset_vbr, k4
add k4, k0
jmp @k0
/* restore mmu and cache state if needed */
mov.l @(SH_SLEEP_MODE, r5), r0
tst #SUSP_SH_MMU, r0
bt skip_restore_mmu
/* restore mmu state */
bsr restore_register
mov #SH_SLEEP_REG_PTEH, r0
bsr restore_register
mov #SH_SLEEP_REG_PTEL, r0
bsr restore_register
mov #SH_SLEEP_REG_TTB, r0
bsr restore_register
mov #SH_SLEEP_REG_TEA, r0
bsr restore_register
mov #SH_SLEEP_REG_PTEA, r0
bsr restore_register
mov #SH_SLEEP_REG_PASCR, r0
bsr restore_register
mov #SH_SLEEP_REG_IRMCR, r0
bsr restore_register
mov #SH_SLEEP_REG_MMUCR, r0
icbi @r0
/* restore cache settings */
bsr restore_register
mov #SH_SLEEP_REG_RAMCR, r0
icbi @r0
bsr restore_register
mov #SH_SLEEP_REG_CCR, r0
icbi @r0
skip_restore_mmu:
rte
nop
.balign 4
saved_mode: .long 0
saved_spc: .long 0
saved_sr: .long 0
saved_vbr: .long 0
offset_vbr: .long 0x600
#ifdef CONFIG_CPU_SUBTYPE_SH7724
dben_reg: .long 0xfd000010 /* DBEN */
dben_data0: .long 0
dben_data1: .long 1
dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */
dbrfpdn0_data0: .long 0
dbrfpdn0_data1: .long 1
dbrfpdn0_data2: .long 0x00010000
dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */
dbcmdcnt_data0: .long 2
dbcmdcnt_data1: .long 4
#else
1: .long 0xfe400008 /* SDCR0 */
2: .long 0x00000400
3: .long 0xffff7fff
4: .long 0xfffffbff
#endif
5: .long 0xa4150020 /* STBCR */
6: .long 0xfe40001c /* RTCOR */
7: .long 0xfe400018 /* RTCNT */
8: .long 0xa55a0000
/* interrupt vector @ 0x600 */
.balign 0x400,0,0x400
.long 0xdeadbeef
.balign 0x200,0,0x200
bra restore_jump_vbr
restore_register:
add #SH_SLEEP_BASE_DATA, r0
mov.l @(r0, r5), r1
add #-SH_SLEEP_BASE_DATA, r0
add #SH_SLEEP_BASE_ADDR, r0
mov.l @(r0, r5), r0
mov.l r1, @r0
rts
nop
sh_mobile_standby_end:
ENTRY(sh_mobile_standby_size)
.long sh_mobile_standby_end - sh_mobile_standby
.balign 4
1: .long ~0x7ff
ENTRY(sh_mobile_sleep_resume_end)
/*
* arch/sh/kernel/cpu/ubc.S
*
* Set of management routines for the User Break Controller (UBC)
*
* Copyright (C) 2002 Paul Mundt
*
* 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.
*/
#include <linux/linkage.h>
#include <asm/ubc.h>
#define STBCR2 0xffc00010
ENTRY(ubc_sleep)
mov #0, r0
mov.l 1f, r1 ! Zero out UBC_BBRA ..
mov.w r0, @r1
mov.l 2f, r1 ! .. same for BBRB ..
mov.w r0, @r1
mov.l 3f, r1 ! .. and again for BRCR.
mov.w r0, @r1
mov.w @r1, r0 ! Dummy read BRCR
mov.l 4f, r1 ! Set MSTP5 in STBCR2
mov.b @r1, r0
or #0x01, r0
mov.b r0, @r1
mov.b @r1, r0 ! Two dummy reads ..
mov.b @r1, r0
rts
nop
ENTRY(ubc_wakeup)
mov.l 4f, r1 ! Clear MSTP5
mov.b @r1, r0
and #0xfe, r0
mov.b r0, @r1
mov.b @r1, r0 ! Two more dummy reads ..
mov.b @r1, r0
rts
nop
1: .long UBC_BBRA
2: .long UBC_BBRB
3: .long UBC_BRCR
4: .long STBCR2
/*
* DMA mapping support for platforms lacking IOMMUs.
*
* Copyright (C) 2009 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/dma-mapping.h>
#include <linux/io.h>
static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction dir,
struct dma_attrs *attrs)
{
dma_addr_t addr = page_to_phys(page) + offset;
WARN_ON(size == 0);
dma_cache_sync(dev, page_address(page) + offset, size, dir);
return addr;
}
static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
int nents, enum dma_data_direction dir,
struct dma_attrs *attrs)
{
struct scatterlist *s;
int i;
WARN_ON(nents == 0 || sg[0].length == 0);
for_each_sg(sg, s, nents, i) {
BUG_ON(!sg_page(s));
dma_cache_sync(dev, sg_virt(s), s->length, dir);
s->dma_address = sg_phys(s);
s->dma_length = s->length;
}
return nents;
}
#ifdef CONFIG_DMA_NONCOHERENT
static void nommu_sync_single(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir)
{
dma_cache_sync(dev, phys_to_virt(addr), size, dir);
}
static void nommu_sync_sg(struct device *dev, struct scatterlist *sg,
int nelems, enum dma_data_direction dir)
{
struct scatterlist *s;
int i;
for_each_sg(sg, s, nelems, i)
dma_cache_sync(dev, sg_virt(s), s->length, dir);
}
#endif
struct dma_map_ops nommu_dma_ops = {
.alloc_coherent = dma_generic_alloc_coherent,
.free_coherent = dma_generic_free_coherent,
.map_page = nommu_map_page,
.map_sg = nommu_map_sg,
#ifdef CONFIG_DMA_NONCOHERENT
.sync_single_for_device = nommu_sync_single,
.sync_sg_for_device = nommu_sync_sg,
#endif
.is_phys = 1,
};
void __init no_iommu_init(void)
{
if (dma_ops)
return;
dma_ops = &nommu_dma_ops;
}
This diff is collapsed.
......@@ -133,7 +133,7 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
tst #_TIF_SIGPENDING, r0
work_notifysig:
bt/s __restore_all
mov r15, r4
......
......@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
return ftrace_replaced_code;
}
/*
* Modifying code must take extra care. On an SMP machine, if
* the code being modified is also being executed on another CPU
* that CPU will have undefined results and possibly take a GPF.
* We use kstop_machine to stop other CPUS from exectuing code.
* But this does not stop NMIs from happening. We still need
* to protect against that. We separate out the modification of
* the code to take care of this.
*
* Two buffers are added: An IP buffer and a "code" buffer.
*
* 1) Put the instruction pointer into the IP buffer
* and the new code into the "code" buffer.
* 2) Wait for any running NMIs to finish and set a flag that says
* we are modifying code, it is done in an atomic operation.
* 3) Write the code
* 4) clear the flag.
* 5) Wait for any running NMIs to finish.
*
* If an NMI is executed, the first thing it does is to call
* "ftrace_nmi_enter". This will check if the flag is set to write
* and if it is, it will write what is in the IP and "code" buffers.
*
* The trick is, it does not matter if everyone is writing the same
* content to the code location. Also, if a CPU is executing code
* it is OK to write to that code location if the contents being written
* are the same as what exists.
*/
#define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */
static atomic_t nmi_running = ATOMIC_INIT(0);
static int mod_code_status; /* holds return value of text write */
static void *mod_code_ip; /* holds the IP to write to */
static void *mod_code_newcode; /* holds the text to write to the IP */
static unsigned nmi_wait_count;
static atomic_t nmi_update_count = ATOMIC_INIT(0);
int ftrace_arch_read_dyn_info(char *buf, int size)
{
int r;
r = snprintf(buf, size, "%u %u",
nmi_wait_count,
atomic_read(&nmi_update_count));
return r;
}
static void clear_mod_flag(void)
{
int old = atomic_read(&nmi_running);
for (;;) {
int new = old & ~MOD_CODE_WRITE_FLAG;
if (old == new)
break;
old = atomic_cmpxchg(&nmi_running, old, new);
}
}
static void ftrace_mod_code(void)
{
/*
* Yes, more than one CPU process can be writing to mod_code_status.
* (and the code itself)
* But if one were to fail, then they all should, and if one were
* to succeed, then they all should.
*/
mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode,
MCOUNT_INSN_SIZE);
/* if we fail, then kill any new writers */
if (mod_code_status)
clear_mod_flag();
}
void ftrace_nmi_enter(void)
{
if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) {
smp_rmb();
ftrace_mod_code();
atomic_inc(&nmi_update_count);
}
/* Must have previous changes seen before executions */
smp_mb();
}
void ftrace_nmi_exit(void)
{
/* Finish all executions before clearing nmi_running */
smp_mb();
atomic_dec(&nmi_running);
}
static void wait_for_nmi_and_set_mod_flag(void)
{
if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG))
return;
do {
cpu_relax();
} while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG));
nmi_wait_count++;
}
static void wait_for_nmi(void)
{
if (!atomic_read(&nmi_running))
return;
do {
cpu_relax();
} while (atomic_read(&nmi_running));
nmi_wait_count++;
}
static int
do_ftrace_mod_code(unsigned long ip, void *new_code)
{
mod_code_ip = (void *)ip;
mod_code_newcode = new_code;
/* The buffers need to be visible before we let NMIs write them */
smp_mb();
wait_for_nmi_and_set_mod_flag();
/* Make sure all running NMIs have finished before we write the code */
smp_mb();
ftrace_mod_code();
/* Make sure the write happens before clearing the bit */
smp_mb();
clear_mod_flag();
wait_for_nmi();
return mod_code_status;
}
static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
unsigned char *new_code)
{
......@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code,
return -EINVAL;
/* replace the text with the new text */
if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE))
if (do_ftrace_mod_code(ip, new_code))
return -EPERM;
flush_icache_range(ip, ip + MCOUNT_INSN_SIZE);
......
......@@ -33,7 +33,7 @@ ENTRY(empty_zero_page)
.long 1 /* LOADER_TYPE */
.long 0x00000000 /* INITRD_START */
.long 0x00000000 /* INITRD_SIZE */
#ifdef CONFIG_32BIT
#if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED)
.long 0x53453f00 + 32 /* "SE?" = 32 bit */
#else
.long 0x53453f00 + 29 /* "SE?" = 29 bit */
......
......@@ -21,7 +21,7 @@
#include <asm/atomic.h>
static int hlt_counter;
void (*pm_idle)(void);
void (*pm_idle)(void) = NULL;
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
......@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused)
}
__setup("hlt", hlt_setup);
static inline int hlt_works(void)
{
return !hlt_counter;
}
/*
* On SMP it's slightly faster (but much more power-consuming!)
* to poll the ->work.need_resched flag instead of waiting for the
* cross-CPU IPI to arrive. Use this option with caution.
*/
static void poll_idle(void)
{
local_irq_enable();
while (!need_resched())
cpu_relax();
}
void default_idle(void)
{
if (!hlt_counter) {
if (hlt_works()) {
clear_thread_flag(TIF_POLLING_NRFLAG);
smp_mb__after_clear_bit();
set_bl_bit();
stop_critical_timings();
while (!need_resched())
if (!need_resched()) {
local_irq_enable();
cpu_sleep();
} else
local_irq_enable();
start_critical_timings();
clear_bl_bit();
set_thread_flag(TIF_POLLING_NRFLAG);
} else
while (!need_resched())
cpu_relax();
poll_idle();
}
/*
* The idle thread. There's no useful work to be done, so just try to conserve
* power and have a low exit latency (ie sit in a loop waiting for somebody to
* say that they'd like to reschedule)
*/
void cpu_idle(void)
{
unsigned int cpu = smp_processor_id();
set_thread_flag(TIF_POLLING_NRFLAG);
/* endless idle loop with no priority at all */
while (1) {
void (*idle)(void) = pm_idle;
tick_nohz_stop_sched_tick(1);
if (!idle)
idle = default_idle;
while (!need_resched() && cpu_online(cpu)) {
check_pgt_cache();
rmb();
tick_nohz_stop_sched_tick(1);
while (!need_resched())
idle();
tick_nohz_restart_sched_tick();
local_irq_disable();
/* Don't trace irqs off for idle */
stop_critical_timings();
pm_idle();
/*
* Sanity check to ensure that pm_idle() returns
* with IRQs enabled
*/
WARN_ON(irqs_disabled());
start_critical_timings();
}
tick_nohz_restart_sched_tick();
preempt_enable_no_resched();
schedule();
preempt_disable();
check_pgt_cache();
}
}
void __cpuinit select_idle_routine(void)
{
/*
* If a platform has set its own idle routine, leave it alone.
*/
if (pm_idle)
return;
if (hlt_works())
pm_idle = default_idle;
else
pm_idle = poll_idle;
}
static void do_nothing(void *unused)
{
}
......
......@@ -24,7 +24,7 @@
#define dummy_read()
#endif
unsigned long generic_io_base;
unsigned long generic_io_base = 0;
u8 generic_inb(unsigned long port)
{
......@@ -147,8 +147,10 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count)
void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
{
#ifdef P1SEG
if (PXSEG(addr) >= P1SEG)
return (void __iomem *)addr;
#endif
return (void __iomem *)(addr + generic_io_base);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs)
*/
int machine_kexec_prepare(struct kimage *image)
{
/* older versions of kexec-tools are passing
* the zImage entry point as a virtual address.
*/
if (image->start != PHYSADDR(image->start))
return -EINVAL; /* upgrade your kexec-tools */
return 0;
}
......
......@@ -135,5 +135,9 @@ void __init sh_mv_setup(void)
if (!sh_mv.mv_nr_irqs)
sh_mv.mv_nr_irqs = NR_IRQS;
#ifdef P2SEG
__set_io_port_base(P2SEG);
#else
__set_io_port_base(0);
#endif
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment