Commit 55a7d4b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-4.2' of git://git.sourceforge.jp/gitroot/uclinux-h8/linux

Pull Renesas H8/300 architecture re-introduction from Yoshinori Sato.

We dropped arch/h8300 two years ago as stale and old, this is a new and
more modern rewritten arch support for the same architecture.

* tag 'for-4.2' of git://git.sourceforge.jp/gitroot/uclinux-h8/linux: (27 commits)
  h8300: fix typo.
  h8300: Always build dtb
  h8300: Remove ARCH_WANT_IPC_PARSE_VERSION
  sh-sci: Get register size from platform device
  clk: h8300: fix error handling in h8s2678_pll_clk_setup()
  h8300: Symbol name fix
  h8300: devicetree source
  h8300: configs
  h8300: IRQ chip driver
  h8300: clocksource
  h8300: clock driver
  h8300: Build scripts
  h8300: library functions
  h8300: Memory management
  h8300: miscellaneous functions
  h8300: process helpers
  h8300: compressed image support
  h8300: Low level entry
  h8300: kernel startup
  h8300: Interrupt and exceptions
  ...
parents aefbef10 07834743
...@@ -3219,11 +3219,6 @@ N: Dipankar Sarma ...@@ -3219,11 +3219,6 @@ N: Dipankar Sarma
E: dipankar@in.ibm.com E: dipankar@in.ibm.com
D: RCU D: RCU
N: Yoshinori Sato
E: ysato@users.sourceforge.jp
D: uClinux for Renesas H8/300 (H8300)
D: http://uclinux-h8.sourceforge.jp/
N: Hannu Savolainen N: Hannu Savolainen
E: hannu@opensound.com E: hannu@opensound.com
D: Maintainer of the sound drivers until 2.1.x days. D: Maintainer of the sound drivers until 2.1.x days.
......
* Renesas H8/300 divider clock
Required Properties:
- compatible: Must be "renesas,sh73a0-h8300-div-clock"
- clocks: Reference to the parent clocks ("extal1" and "extal2")
- #clock-cells: Must be 1
- reg: Base address and length of the divide rate selector
- renesas,width: bit width of selector
Example
-------
cclk: cclk {
compatible = "renesas,h8300-div-clock";
clocks = <&xclk>;
#clock-cells = <0>;
reg = <0xfee01b 2>;
renesas,width = <2>;
};
Renesas H8S2678 PLL clock
This device is Clock multiplyer
Required Properties:
- compatible: Must be "renesas,h8s2678-pll-clock"
- clocks: Reference to the parent clocks
- #clock-cells: Must be 0
- reg: Two rate selector (Multiply / Divide) register address
Example
-------
pllclk: pllclk {
compatible = "renesas,h8s2678-pll-clock";
clocks = <&xclk>;
#clock-cells = <0>;
reg = <0xfee03b 2>, <0xfee045 2>;
};
* H8/300 CPU bindings
Required properties:
- compatible: Compatible property value should be "renesas,h8300".
- clock-frequency: Contains the clock frequency for CPU, in Hz.
Example:
cpu@0 {
compatible = "renesas,h8300";
clock-frequency = <20000000>;
};
* H8/300H Interrupt controller
Required properties:
- compatible: has to be "renesas,h8300h-intc", "renesas,h8300-intc" as fallback.
- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
interrupts.txt in this directory
- regs: Base address of interrupt controller registers.
Optional properties:
- any properties, listed in interrupts.txt, and any standard resource allocation
properties
Example:
h8intc: interrupt-controller@fee012 {
compatible = "renesas,h8300h-intc", "renesas,h8300-intc";
#interrupt-cells = <2>;
interrupt-controller;
reg = <0xfee012 7>;
};
* H8S Interrupt controller
Required properties:
- compatible: has to be "renesas,h8s-intc", "renesas,h8300-intc" as fallback.
- #interrupt-cells: has to be <2>: an interrupt index and flags, as defined in
interrupts.txt in this directory
- regs: Base address of interrupt controller registers.
Optional properties:
- any properties, listed in interrupts.txt, and any standard resource allocation
properties
Example:
h8intc: interrupt-controller@fffe00 {
compatible = "renesas,h8s-intc", "renesas,h8300-intc";
#interrupt-cells = <2>;
interrupt-controller;
reg = <0xfffe00 24>;
};
* H8/300 bus controller
Required properties:
- compatible: Must be "renesas,h8300-bsc".
- reg: Base address and length of BSC registers.
Example.
bsc: memory-controller@fee01e {
compatible = "renesas,h8300h-bsc", "renesas,h8300-bsc";
reg = <0xfee01e 8>;
};
...@@ -29,6 +29,7 @@ Required properties: ...@@ -29,6 +29,7 @@ Required properties:
- "renesas,scifa" for generic SCIFA compatible UART. - "renesas,scifa" for generic SCIFA compatible UART.
- "renesas,scifb" for generic SCIFB compatible UART. - "renesas,scifb" for generic SCIFB compatible UART.
- "renesas,hscif" for generic HSCIF compatible UART. - "renesas,hscif" for generic HSCIF compatible UART.
- "renesas,sci" for generic SCI compatible UART.
When compatible with the generic version, nodes must list the When compatible with the generic version, nodes must list the
SoC-specific version corresponding to the platform first followed by the SoC-specific version corresponding to the platform first followed by the
......
* Renesas H8/300 16bit timer
The 16bit timer is a 16bit timer/counter with configurable clock inputs and
programmable compare match.
Required Properties:
- compatible: must contain "renesas,16bit-timer"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, IMIA
- clocks: a list of phandle, one for each entry in clock-names.
- clock-names: must contain "peripheral_clk" for the functional clock.
- renesas,channel: timer channel number.
Example:
timer16: timer@ffff68 {
compatible = "reneas,16bit-timer";
reg = <0xffff68 8>, <0xffff60 8>;
interrupts = <24>;
renesas,channel = <0>;
clocks = <&pclk>;
clock-names = "peripheral_clk";
};
* Renesas H8/300 8bit timer
The 8bit timer is a 8bit timer/counter with configurable clock inputs and
programmable compare match.
This implement only supported cascade mode.
Required Properties:
- compatible: must contain "renesas,8bit-timer"
- reg: base address and length of the registers block for the timer module.
- interrupts: interrupt-specifier for the timer, CMIA and TOVI
- clocks: a list of phandle, one for each entry in clock-names.
- clock-names: must contain "fck" for the functional clock.
Example:
timer8_0: timer@ffff80 {
compatible = "renesas,8bit-timer";
reg = <0xffff80 10>;
interrupts = <36>;
clocks = <&fclk>;
clock-names = "fck";
};
* Renesas H8/300 Timer Pluse Unit
The TPU is a 16bit timer/counter with configurable clock inputs and
programmable compare match.
This implementation support only cascade mode.
Required Properties:
- compatible: must contain "renesas,tpu"
- reg: base address and length of the registers block in 2 channel.
- clocks: a list of phandle, one for each entry in clock-names.
- clock-names: must contain "peripheral_clk" for the functional clock.
Example:
tpu: tpu@ffffe0 {
compatible = "renesas,tpu";
reg = <0xffffe0 16>, <0xfffff0 12>;
clocks = <&pclk>;
clock-names = "peripheral_clk";
};
...@@ -4549,6 +4549,17 @@ T: git git://linuxtv.org/media_tree.git ...@@ -4549,6 +4549,17 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained S: Maintained
F: drivers/media/usb/stk1160/ F: drivers/media/usb/stk1160/
H8/300 ARCHITECTURE
M: Yoshinori Sato <ysato@users.sourceforge.jp>
L: uclinux-h8-devel@lists.sourceforge.jp
W: http://uclinux-h8.sourceforge.jp
T: git git://git.sourceforge.jp/gitroot/uclinux-h8/linux.git
S: Maintained
F: arch/h8300/
F: drivers/clocksource/h8300_*.c
F: drivers/clk/h8300/
F: drivers/irqchip/irq-renesas-h8*.c
HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
M: Frank Seidel <frank@f-seidel.de> M: Frank Seidel <frank@f-seidel.de>
L: platform-driver-x86@vger.kernel.org L: platform-driver-x86@vger.kernel.org
......
config H8300
def_bool y
select GENERIC_ATOMIC64
select HAVE_UID16
select VIRT_TO_BUS
select GENERIC_IRQ_SHOW
select FRAME_POINTER
select GENERIC_CPU_DEVICES
select MODULES_USE_ELF_RELA
select GENERIC_CLOCKEVENTS
select CLKDEV_LOOKUP
select COMMON_CLK
select ARCH_WANT_FRAME_POINTERS
select OF
select OF_IRQ
select OF_EARLY_FLATTREE
select HAVE_MEMBLOCK
select HAVE_DMA_ATTRS
config RWSEM_GENERIC_SPINLOCK
def_bool y
config GENERIC_HWEIGHT
def_bool y
config NO_IOPORT_MAP
def_bool y
config GENERIC_CSUM
def_bool y
config HZ
int
default 100
config NR_CPUS
int
default 1
source "init/Kconfig"
source "kernel/Kconfig.freezer"
source "arch/h8300/Kconfig.cpu"
menu "Kernel Features"
source "kernel/Kconfig.preempt"
source "mm/Kconfig"
endmenu
menu "Executable file formats"
source "fs/Kconfig.binfmt"
endmenu
source "net/Kconfig"
source "drivers/Kconfig"
source "fs/Kconfig"
menu "Kernel hacking"
source "lib/Kconfig.debug"
endmenu
source "security/Kconfig"
source "crypto/Kconfig"
source "lib/Kconfig"
config CPU_H8300H
bool
config CPU_H8S
bool
config H83069
bool
select CPU_H8300H
select H8300_TMR16
select RENESAS_H8300H_INTC
config H8S2678
bool
select CPU_H8S
select H8300_TPU
select RENESAS_H8S_INTC
config RAMKERNEL
bool
config ROMKERNEL
bool
menu "Processor type and features"
choice
prompt "H8/300 platform"
config H8300_AE3068
bool "AE-3068/69"
select H83069
select RAMKERNEL
help
AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
More Information. (Japanese Only)
<http://akizukidenshi.com/catalog/default.aspx>
AE-3068/69 Evaluation Board Support
More Information.
<http://www.microtronique.com/ae3069lan.htm>
config H8300_H8MAX
bool "H8MAX"
select H83069
select RAMKERNEL
select HAVE_IDE
help
H8MAX Evaluation Board Support
More Information. (Japanese Only)
<http://strawberry-linux.com/h8/index.html>
config H8300_KANEBEBE
bool "KaneBebe"
select H83069
select RAMKERNEL
help
KaneBebe Evalition Board Support
More Information. (Japanese Only)
<http://www.nissin-tech.com/2009/10/uclinuxkane-bebe-h83069f.html>
config H8300H_SIM
bool "H8/300H GDB Simulator"
select H83069
select ROMKERNEL
help
GDB Simulator Support
More Information.
<http://sourceware.org/sid/>
config H8S_EDOSK2674
bool "EDOSK-2674"
select H8S2678
select RAMKERNEL
help
Renesas EDOSK-2674 Evaluation Board Support
More Information.
<http://www.azpower.com/H8-uClinux/index.html>
<http://www.renesas.eu/products/tools/introductory_evaluation_tools/evaluation_development_os_kits/edosk2674r/edosk2674r_software_tools_root.jsp>
config H8S_SIM
bool "H8S GDB Simulator"
select H8S2678
select ROMKERNEL
help
GDB Simulator Support
More Information.
<http://sourceware.org/sid/>
endchoice
config H8300_BUILTIN_DTB
string "Builtin DTB"
default ""
config OFFSET
hex "Load offset"
default 0
endmenu
#
# arch/h8300/Makefile
#
# 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.
#
# (C) Copyright 2002-2015 Yoshinori Sato <ysato@users.sourceforge.jp>
#
cflags-$(CONFIG_CPU_H8300H) := -mh
aflags-$(CONFIG_CPU_H8300H) := -mh -Wa,--mach=h8300h
ldflags-$(CONFIG_CPU_H8300H) := -mh8300helf_linux
cflags-$(CONFIG_CPU_H8S) := -ms
aflags-$(CONFIG_CPU_H8S) := -ms -Wa,--mach=h8300s
ldflags-$(CONFIG_CPU_H8S) := -mh8300self_linux
KBUILD_CFLAGS += $(cflags-y)
KBUILD_CFLAGS += -mint32 -fno-builtin
KBUILD_CFLAGS += -D__linux__
KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
KBUILD_AFLAGS += $(aflags-y)
LDFLAGS += $(ldflags-y)
CROSS_COMPILE := h8300-unknown-linux-
core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""'
core-y += arch/h8300/boot/dts/
endif
libs-y += arch/$(ARCH)/lib/
boot := arch/h8300/boot
%.dtb %.dtb.S %.dtb.o: | scripts
$(Q)$(MAKE) $(build)=arch/h8300/boot/dts arch/h8300/boot/dts/$@
PHONY += dtbs
dtbs: scripts
$(Q)$(MAKE) $(build)=arch/h8300/boot/dts
archmrproper:
archclean:
$(Q)$(MAKE) $(clean)=$(boot)
vmlinux.srec vmlinux.bin zImage uImage.bin: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
define archhelp
@echo 'vmlinux.bin - Create raw binary'
@echo 'vmlinux.srec - Create srec binary'
@echo 'zImage - Compressed kernel image'
endef
# arch/h8300/boot/Makefile
targets := vmlinux.srec vmlinux.bin zImage
subdir- := compressed
OBJCOPYFLAGS_vmlinux.srec := -Osrec
OBJCOPYFLAGS_vmlinux.bin := -Obinary
OBJCOPYFLAGS_zImage := -O binary -R .note -R .comment -R .stab -R .stabstr -S
UIMAGE_LOADADDR = $(CONFIG_RAMBASE)
UIMAGE_ENTRYADDR = $(shell /bin/bash -c 'printf "0x%08x" \
$$[$(CONFIG_RAMBASE) + $(CONFIG_OFFSET)]')
$(obj)/vmlinux.srec $(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/zImage: $(obj)/compressed/vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/compressed/vmlinux: FORCE
$(Q)$(MAKE) $(build)=$(obj)/compressed $@
$(obj)/uImage.bin: $(obj)/vmlinux.bin
$(call if_changed,uimage,none)
CLEAN_FILES += arch/$(ARCH)/vmlinux.bin arch/$(ARCH)/vmlinux.srec arch/$(ARCH)/uImage.bin
#
# linux/arch/sh/boot/compressed/Makefile
#
# create a compressed vmlinux image from the original vmlinux
#
targets := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o
OBJECTS = $(obj)/head.o $(obj)/misc.o
#
# IMAGE_OFFSET is the load offset of the compression loader
# Assign dummy values if these 2 variables are not defined,
# in order to suppress error message.
#
CONFIG_MEMORY_START ?= 0x00400000
CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
IMAGE_OFFSET := $(shell printf "0x%08x" $$(($(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET))))
LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
$(call if_changed,ld)
@:
$(obj)/vmlinux.bin: vmlinux FORCE
$(call if_changed,objcopy)
$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
$(call if_changed,gzip)
LDFLAGS_piggy.o := -r --format binary --oformat elf32-h8300-linux -T
OBJCOPYFLAGS := -O binary
$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE
$(call if_changed,ld)
/*
* linux/arch/h8300/boot/compressed/head.S
*
* Copyright (C) 2006 Yoshinori Sato
*/
#include <linux/linkage.h>
.section .text..startup,"ax"
.global startup
startup:
mov.l er0, er4
mov.l er0, sp
mov.l #__sbss, er0
mov.l #__ebss, er1
sub.l er0, er1
shlr er1
shlr er1
sub.l er2, er2
1:
mov.l er2, @er0
adds #4, er0
dec.l #1, er1
bne 1b
jsr @decompress_kernel
mov.l er4, er0
jmp @0x400000
.align 9
fake_headers_as_bzImage:
.word 0
.ascii "HdrS" ; header signature
.word 0x0202 ; header version number (>= 0x0105)
; or else old loadlin-1.5 will fail)
.word 0 ; default_switch
.word 0 ; SETUPSEG
.word 0x1000
.word 0 ; pointing to kernel version string
.byte 0 ; = 0, old one (LILO, Loadlin,
; 0xTV: T=0 for LILO
; V = version
.byte 1 ; Load flags bzImage=1
.word 0x8000 ; size to move, when setup is not
.long 0x100000 ; 0x100000 = default for big kernel
.long 0 ; address of loaded ramdisk image
.long 0 ; its size in bytes
.end
/*
* arch/h8300/boot/compressed/misc.c
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
*
* malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994
*
* Adapted for h8300 by Yoshinori Sato 2006
*/
#include <asm/uaccess.h>
/*
* gzip declarations
*/
#define OF(args) args
#define STATIC static
#undef memset
#undef memcpy
#define memzero(s, n) memset((s), (0), (n))
extern int _end;
static unsigned long free_mem_ptr;
static unsigned long free_mem_end_ptr;
extern char input_data[];
extern int input_len;
static unsigned char *output;
#define HEAP_SIZE 0x10000
#include "../../../../lib/decompress_inflate.c"
void *memset(void *s, int c, size_t n)
{
int i;
char *ss = (char *)s;
for (i = 0; i < n; i++)
ss[i] = c;
return s;
}
void *memcpy(void *dest, const void *src, size_t n)
{
int i;
char *d = (char *)dest, *s = (char *)src;
for (i = 0; i < n; i++)
d[i] = s[i];
return dest;
}
static void error(char *x)
{
while (1)
; /* Halt */
}
#define STACK_SIZE (4096)
long user_stack[STACK_SIZE];
long *stack_start = &user_stack[STACK_SIZE];
void decompress_kernel(void)
{
free_mem_ptr = (unsigned long)&_end;
free_mem_end_ptr = free_mem_ptr + HEAP_SIZE;
decompress(input_data, input_len, NULL, NULL, output, NULL, error);
}
SECTIONS
{
.text :
{
__stext = . ;
__text = .;
*(.text..startup)
*(.text)
__etext = . ;
}
.rodata :
{
*(.rodata)
}
.data :
{
__sdata = . ;
___data_start = . ;
*(.data.*)
}
.bss :
{
. = ALIGN(0x4) ;
__sbss = . ;
*(.bss*)
. = ALIGN(0x4) ;
__ebss = . ;
__end = . ;
}
}
SECTIONS
{
.data : {
input_len = .;
LONG(input_data_end - input_data) input_data = .;
*(.data)
input_data_end = .;
}
}
ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""'
BUILTIN_DTB := $(patsubst "%",%,$(CONFIG_H8300_BUILTIN_DTB)).dtb.o
endif
obj-y += $(BUILTIN_DTB)
dtb-$(CONFIG_H8300H_SIM) := h8300h_sim.dtb
dtb-$(CONFIG_H8S_SIM) := h8s_sim.dtb
dtb-$(CONFIG_H8S_EDOSK2674) := edosk2674.dtb
always := $(dtb-y)
clean-files := *.dtb.S *.dtb
/dts-v1/;
/ {
compatible = "renesas,edosk2674";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&h8intc>;
chosen {
bootargs = "console=ttySC2,38400";
stdout-path = <&sci2>;
};
aliases {
serial0 = &sci0;
serial1 = &sci1;
serial2 = &sci2;
};
xclk: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <33333333>;
clock-output-names = "xtal";
};
pllclk: pllclk {
compatible = "renesas,h8s2678-pll-clock";
clocks = <&xclk>;
#clock-cells = <0>;
reg = <0xfee03b 2>, <0xfee045 2>;
};
core_clk: core_clk {
compatible = "renesas,h8300-div-clock";
clocks = <&pllclk>;
#clock-cells = <0>;
reg = <0xfee03b 2>;
renesas,width = <3>;
};
fclk: fclk {
compatible = "fixed-factor-clock";
clocks = <&core_clk>;
#clock-cells = <0>;
clock-div = <1>;
clock-mult = <1>;
};
memory@400000 {
device_type = "memory";
reg = <0x400000 0x800000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "renesas,h8300";
clock-frequency = <33333333>;
};
};
h8intc: interrupt-controller@fffe00 {
compatible = "renesas,h8s-intc", "renesas,h8300-intc";
#interrupt-cells = <2>;
interrupt-controller;
reg = <0xfffe00 24>;
};
bsc: memory-controller@fffec0 {
compatible = "renesas,h8s-bsc", "renesas,h8300-bsc";
reg = <0xfffec0 24>;
};
tpu: timer@ffffe0 {
compatible = "renesas,tpu";
reg = <0xffffe0 16>, <0xfffff0 12>;
clocks = <&fclk>;
clock-names = "fck";
};
timer8: timer@ffffb0 {
compatible = "renesas,8bit-timer";
reg = <0xffffb0 10>;
interrupts = <72 0>;
clocks = <&fclk>;
clock-names = "fck";
};
sci0: serial@ffff78 {
compatible = "renesas,sci";
reg = <0xffff78 8>;
interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
sci1: serial@ffff80 {
compatible = "renesas,sci";
reg = <0xffff80 8>;
interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
sci2: serial@ffff88 {
compatible = "renesas,sci";
reg = <0xffff88 8>;
interrupts = <96 0>, <97 0>, <98 0>, <99 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
};
/dts-v1/;
/ {
compatible = "gnu,gdbsim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&h8intc>;
chosen {
bootargs = "earlyprintk=h8300-sim";
stdout-path = <&sci0>;
};
aliases {
serial0 = &sci0;
serial1 = &sci1;
};
xclk: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <20000000>;
clock-output-names = "xtal";
};
core_clk: core_clk {
compatible = "renesas,h8300-div-clock";
clocks = <&xclk>;
#clock-cells = <0>;
reg = <0xfee01b 2>;
renesas,width = <2>;
};
fclk: fclk {
compatible = "fixed-factor-clock";
clocks = <&core_clk>;
#clock-cells = <0>;
clock-div = <1>;
clock-mult = <1>;
};
memory@400000 {
device_type = "memory";
reg = <0x400000 0x400000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "renesas,h8300";
clock-frequency = <20000000>;
};
};
h8intc: interrupt-controller@fee012 {
compatible = "renesas,h8300h-intc", "renesas,h8300-intc";
#interrupt-cells = <2>;
interrupt-controller;
reg = <0xfee012 7>;
};
bsc: memory-controller@fee01e {
compatible = "renesas,h8300h-bsc", "renesas,h8300-bsc";
reg = <0xfee01e 8>;
};
timer8: timer@ffff80 {
compatible = "renesas,8bit-timer";
reg = <0xffff80 10>;
interrupts = <36 0>;
clocks = <&fclk>;
clock-names = "fck";
};
timer16: timer@ffff68 {
compatible = "renesas,16bit-timer";
reg = <0xffff68 8>, <0xffff60 8>;
interrupts = <24 0>;
renesas,channel = <0>;
clocks = <&fclk>;
clock-names = "fck";
};
sci0: serial@ffffb0 {
compatible = "renesas,sci";
reg = <0xffffb0 8>;
interrupts = <52 0>, <53 0>, <54 0>, <55 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
sci1: serial@ffffb8 {
compatible = "renesas,sci";
reg = <0xffffb8 8>;
interrupts = <56 0>, <57 0>, <58 0>, <59 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
};
/dts-v1/;
/ {
compatible = "gnu,gdbsim";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&h8intc>;
chosen {
bootargs = "earlyprintk=h8300-sim";
stdout-path = <&sci0>;
};
aliases {
serial0 = &sci0;
serial1 = &sci1;
};
xclk: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <33333333>;
clock-output-names = "xtal";
};
pllclk: pllclk {
compatible = "renesas,h8s2678-pll-clock";
clocks = <&xclk>;
#clock-cells = <0>;
reg = <0xfee03b 2>, <0xfee045 2>;
};
core_clk: core_clk {
compatible = "renesas,h8300-div-clock";
clocks = <&pllclk>;
#clock-cells = <0>;
reg = <0xfee03b 2>;
renesas,width = <3>;
};
fclk: fclk {
compatible = "fixed-factor-clock";
clocks = <&core_clk>;
#clock-cells = <0>;
clock-div = <1>;
clock-mult = <1>;
};
memory@400000 {
device_type = "memory";
reg = <0x400000 0x800000>;
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "renesas,h8300";
clock-frequency = <33333333>;
};
};
h8intc: interrupt-controller@fffe00 {
compatible = "renesas,h8s-intc", "renesas,h8300-intc";
#interrupt-cells = <2>;
interrupt-controller;
reg = <0xfffe00 24>;
};
bsc: memory-controller@fffec0 {
compatible = "renesas,h8s-bsc", "renesas,h8300-bsc";
reg = <0xfffec0 24>;
};
tpu: timer@ffffe0 {
compatible = "renesas,tpu";
reg = <0xffffe0 16>, <0xfffff0 12>;
clocks = <&fclk>;
clock-names = "fck";
};
timer8: timer@ffffb0 {
compatible = "renesas,8bit-timer";
reg = <0xffffb0 10>;
interrupts = <72 0>;
clocks = <&fclk>;
clock-names = "fck";
};
sci0: serial@ffff78 {
compatible = "renesas,sci";
reg = <0xffff78 8>;
interrupts = <88 0>, <89 0>, <90 0>, <91 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
sci1: serial@ffff80 {
compatible = "renesas,sci";
reg = <0xffff80 8>;
interrupts = <92 0>, <93 0>, <94 0>, <95 0>;
clocks = <&fclk>;
clock-names = "sci_ick";
};
};
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_USELIB is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_UID16 is not set
# CONFIG_SYSFS_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
# CONFIG_ADVISE_SYSCALLS is not set
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLOB=y
# CONFIG_BLOCK is not set
CONFIG_H8S_SIM=y
CONFIG_H8300_BUILTIN_DTB="h8s_sim"
# CONFIG_BINFMT_SCRIPT is not set
CONFIG_BINFMT_FLAT=y
# CONFIG_COREDUMP is not set
# CONFIG_UEVENT_HELPER is not set
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_ALLOW_DEV_COREDUMP is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_UNIX98_PTYS is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
# CONFIG_PROC_FS is not set
# CONFIG_SYSFS is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_DEBUG_INFO=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_USELIB is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_UID16 is not set
# CONFIG_SYSFS_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
# CONFIG_ADVISE_SYSCALLS is not set
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLOB=y
# CONFIG_BLOCK is not set
CONFIG_H8300H_SIM=y
CONFIG_H8300_BUILTIN_DTB="h8300h_sim"
# CONFIG_BINFMT_SCRIPT is not set
CONFIG_BINFMT_FLAT=y
# CONFIG_COREDUMP is not set
# CONFIG_UEVENT_HELPER is not set
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_ALLOW_DEV_COREDUMP is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_UNIX98_PTYS is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
# CONFIG_PROC_FS is not set
# CONFIG_SYSFS is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_DEBUG_INFO=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
# CONFIG_LOCALVERSION_AUTO is not set
# CONFIG_USELIB is not set
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_UID16 is not set
# CONFIG_SYSFS_SYSCALL is not set
# CONFIG_KALLSYMS is not set
# CONFIG_BASE_FULL is not set
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
# CONFIG_SIGNALFD is not set
# CONFIG_TIMERFD is not set
# CONFIG_EVENTFD is not set
# CONFIG_AIO is not set
# CONFIG_ADVISE_SYSCALLS is not set
CONFIG_EMBEDDED=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_COMPAT_BRK is not set
CONFIG_SLOB=y
# CONFIG_BLOCK is not set
CONFIG_H8S_SIM=y
CONFIG_H8300_BUILTIN_DTB="h8s_sim"
# CONFIG_BINFMT_SCRIPT is not set
CONFIG_BINFMT_FLAT=y
# CONFIG_COREDUMP is not set
# CONFIG_UEVENT_HELPER is not set
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
# CONFIG_ALLOW_DEV_COREDUMP is not set
# CONFIG_INPUT is not set
# CONFIG_SERIO is not set
# CONFIG_VT is not set
# CONFIG_UNIX98_PTYS is not set
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
# CONFIG_USB_SUPPORT is not set
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
# CONFIG_PROC_FS is not set
# CONFIG_SYSFS is not set
# CONFIG_MISC_FILESYSTEMS is not set
CONFIG_DEBUG_INFO=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
generic-y += asm-offsets.h
generic-y += auxvec.h
generic-y += barrier.h
generic-y += bugs.h
generic-y += cacheflush.h
generic-y += checksum.h
generic-y += clkdev.h
generic-y += cputime.h
generic-y += current.h
generic-y += delay.h
generic-y += device.h
generic-y += div64.h
generic-y += dma.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
generic-y += fb.h
generic-y += fcntl.h
generic-y += ftrace.h
generic-y += futex.h
generic-y += hardirq.h
generic-y += hash.h
generic-y += hw_irq.h
generic-y += ioctl.h
generic-y += ioctls.h
generic-y += ipcbuf.h
generic-y += irq_regs.h
generic-y += irq_work.h
generic-y += kdebug.h
generic-y += kmap_types.h
generic-y += kvm_para.h
generic-y += linkage.h
generic-y += local.h
generic-y += local64.h
generic-y += mcs_spinlock.h
generic-y += mman.h
generic-y += mmu.h
generic-y += mmu_context.h
generic-y += module.h
generic-y += msgbuf.h
generic-y += param.h
generic-y += parport.h
generic-y += percpu.h
generic-y += pgalloc.h
generic-y += poll.h
generic-y += posix_types.h
generic-y += preempt.h
generic-y += resource.h
generic-y += scatterlist.h
generic-y += sections.h
generic-y += sembuf.h
generic-y += serial.h
generic-y += setup.h
generic-y += shmbuf.h
generic-y += shmparam.h
generic-y += siginfo.h
generic-y += sizes.h
generic-y += socket.h
generic-y += sockios.h
generic-y += spinlock.h
generic-y += stat.h
generic-y += statfs.h
generic-y += swab.h
generic-y += termbits.h
generic-y += termios.h
generic-y += timex.h
generic-y += tlbflush.h
generic-y += trace_clock.h
generic-y += topology.h
generic-y += types.h
generic-y += uaccess.h
generic-y += ucontext.h
generic-y += unaligned.h
generic-y += vga.h
generic-y += xor.h
#ifndef __ARCH_H8300_ATOMIC__
#define __ARCH_H8300_ATOMIC__
#include <linux/types.h>
#include <asm/cmpxchg.h>
/*
* Atomic operations that C can't guarantee us. Useful for
* resource counting etc..
*/
#define ATOMIC_INIT(i) { (i) }
#define atomic_read(v) ACCESS_ONCE((v)->counter)
#define atomic_set(v, i) (((v)->counter) = i)
#include <linux/kernel.h>
static inline int atomic_add_return(int i, atomic_t *v)
{
h8300flags flags;
int ret;
flags = arch_local_irq_save();
ret = v->counter += i;
arch_local_irq_restore(flags);
return ret;
}
#define atomic_add(i, v) atomic_add_return(i, v)
#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
static inline int atomic_sub_return(int i, atomic_t *v)
{
h8300flags flags;
int ret;
flags = arch_local_irq_save();
ret = v->counter -= i;
arch_local_irq_restore(flags);
return ret;
}
#define atomic_sub(i, v) atomic_sub_return(i, v)
#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
static inline int atomic_inc_return(atomic_t *v)
{
h8300flags flags;
int ret;
flags = arch_local_irq_save();
v->counter++;
ret = v->counter;
arch_local_irq_restore(flags);
return ret;
}
#define atomic_inc(v) atomic_inc_return(v)
/*
* atomic_inc_and_test - increment and test
* @v: pointer of type atomic_t
*
* Atomically increments @v by 1
* and returns true if the result is zero, or false for all
* other cases.
*/
#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
static inline int atomic_dec_return(atomic_t *v)
{
h8300flags flags;
int ret;
flags = arch_local_irq_save();
--v->counter;
ret = v->counter;
arch_local_irq_restore(flags);
return ret;
}
#define atomic_dec(v) atomic_dec_return(v)
static inline int atomic_dec_and_test(atomic_t *v)
{
h8300flags flags;
int ret;
flags = arch_local_irq_save();
--v->counter;
ret = v->counter;
arch_local_irq_restore(flags);
return ret == 0;
}
static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
{
int ret;
h8300flags flags;
flags = arch_local_irq_save();
ret = v->counter;
if (likely(ret == old))
v->counter = new;
arch_local_irq_restore(flags);
return ret;
}
static inline int __atomic_add_unless(atomic_t *v, int a, int u)
{
int ret;
h8300flags flags;
flags = arch_local_irq_save();
ret = v->counter;
if (ret != u)
v->counter += a;
arch_local_irq_restore(flags);
return ret;
}
static inline void atomic_clear_mask(unsigned long mask, unsigned long *v)
{
unsigned char ccr;
unsigned long tmp;
__asm__ __volatile__("stc ccr,%w3\n\t"
"orc #0x80,ccr\n\t"
"mov.l %0,%1\n\t"
"and.l %2,%1\n\t"
"mov.l %1,%0\n\t"
"ldc %w3,ccr"
: "=m"(*v), "=r"(tmp)
: "g"(~(mask)), "r"(ccr));
}
static inline void atomic_set_mask(unsigned long mask, unsigned long *v)
{
unsigned char ccr;
unsigned long tmp;
__asm__ __volatile__("stc ccr,%w3\n\t"
"orc #0x80,ccr\n\t"
"mov.l %0,%1\n\t"
"or.l %2,%1\n\t"
"mov.l %1,%0\n\t"
"ldc %w3,ccr"
: "=m"(*v), "=r"(tmp)
: "g"(~(mask)), "r"(ccr));
}
/* Atomic operations are already serializing */
#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()
#endif /* __ARCH_H8300_ATOMIC __ */
#ifndef _H8300_BITOPS_H
#define _H8300_BITOPS_H
/*
* Copyright 1992, Linus Torvalds.
* Copyright 2002, Yoshinori Sato
*/
#include <linux/compiler.h>
#ifdef __KERNEL__
#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif
/*
* Function prototypes to keep gcc -Wall happy
*/
/*
* ffz = Find First Zero in word. Undefined if no zero exists,
* so code should check against ~0UL first..
*/
static inline unsigned long ffz(unsigned long word)
{
unsigned long result;
result = -1;
__asm__("1:\n\t"
"shlr.l %2\n\t"
"adds #1,%0\n\t"
"bcs 1b"
: "=r"(result)
: "0"(result), "r"(word));
return result;
}
#define H8300_GEN_BITOP(FNAME, OP) \
static inline void FNAME(int nr, volatile unsigned long *addr) \
{ \
unsigned char *b_addr; \
unsigned char bit = nr & 7; \
\
b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
if (__builtin_constant_p(nr)) { \
__asm__(OP " %1,%0" : "+WU"(*b_addr) : "i"(nr & 7)); \
} else { \
__asm__(OP " %s1,%0" : "+WU"(*b_addr) : "r"(bit)); \
} \
}
/*
* clear_bit() doesn't provide any barrier for the compiler.
*/
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
H8300_GEN_BITOP(set_bit, "bset")
H8300_GEN_BITOP(clear_bit, "bclr")
H8300_GEN_BITOP(change_bit, "bnot")
#define __set_bit(nr, addr) set_bit((nr), (addr))
#define __clear_bit(nr, addr) clear_bit((nr), (addr))
#define __change_bit(nr, addr) change_bit((nr), (addr))
#undef H8300_GEN_BITOP
static inline int test_bit(int nr, const unsigned long *addr)
{
int ret = 0;
unsigned char *b_addr;
unsigned char bit = nr & 7;
b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3);
if (__builtin_constant_p(nr)) {
__asm__("bld %Z2,%1\n\t"
"rotxl %0\n\t"
: "=r"(ret)
: "WU"(*b_addr), "i"(nr & 7), "0"(ret) : "cc");
} else {
__asm__("btst %w2,%1\n\t"
"beq 1f\n\t"
"inc.l #1,%0\n"
"1:"
: "=r"(ret)
: "WU"(*b_addr), "r"(bit), "0"(ret) : "cc");
}
return ret;
}
#define __test_bit(nr, addr) test_bit(nr, addr)
#define H8300_GEN_TEST_BITOP(FNNAME, OP) \
static inline int FNNAME(int nr, void *addr) \
{ \
int retval = 0; \
char ccrsave; \
unsigned char *b_addr; \
unsigned char bit = nr & 7; \
\
b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
if (__builtin_constant_p(nr)) { \
__asm__("stc ccr,%s2\n\t" \
"orc #0x80,ccr\n\t" \
"bld %4,%1\n\t" \
OP " %4,%1\n\t" \
"rotxl.l %0\n\t" \
"ldc %s2,ccr" \
: "=r"(retval), "+WU" (*b_addr), "=&r"(ccrsave) \
: "0"(retval), "i"(nr & 7) : "cc"); \
} else { \
__asm__("stc ccr,%t3\n\t" \
"orc #0x80,ccr\n\t" \
"btst %s3,%1\n\t" \
OP " %s3,%1\n\t" \
"beq 1f\n\t" \
"inc.l #1,%0\n\t" \
"1:\n" \
"ldc %t3,ccr" \
: "=r"(retval), "+WU" (*b_addr) \
: "0" (retval), "r"(bit) : "cc"); \
} \
return retval; \
} \
\
static inline int __ ## FNNAME(int nr, void *addr) \
{ \
int retval = 0; \
unsigned char *b_addr; \
unsigned char bit = nr & 7; \
\
b_addr = (unsigned char *)addr + ((nr >> 3) ^ 3); \
if (__builtin_constant_p(nr)) { \
__asm__("bld %3,%1\n\t" \
OP " %3,%1\n\t" \
"rotxl.l %0\n\t" \
: "=r"(retval), "+WU"(*b_addr) \
: "0" (retval), "i"(nr & 7)); \
} else { \
__asm__("btst %s3,%1\n\t" \
OP " %s3,%1\n\t" \
"beq 1f\n\t" \
"inc.l #1,%0\n\t" \
"1:" \
: "=r"(retval), "+WU"(*b_addr) \
: "0" (retval), "r"(bit)); \
} \
return retval; \
}
H8300_GEN_TEST_BITOP(test_and_set_bit, "bset")
H8300_GEN_TEST_BITOP(test_and_clear_bit, "bclr")
H8300_GEN_TEST_BITOP(test_and_change_bit, "bnot")
#undef H8300_GEN_TEST_BITOP
#include <asm-generic/bitops/ffs.h>
static inline unsigned long __ffs(unsigned long word)
{
unsigned long result;
result = -1;
__asm__("1:\n\t"
"shlr.l %2\n\t"
"adds #1,%0\n\t"
"bcc 1b"
: "=r" (result)
: "0"(result), "r"(word));
return result;
}
#include <asm-generic/bitops/find.h>
#include <asm-generic/bitops/sched.h>
#include <asm-generic/bitops/hweight.h>
#include <asm-generic/bitops/lock.h>
#include <asm-generic/bitops/le.h>
#include <asm-generic/bitops/ext2-atomic.h>
#endif /* __KERNEL__ */
#include <asm-generic/bitops/fls.h>
#include <asm-generic/bitops/__fls.h>
#include <asm-generic/bitops/fls64.h>
#endif /* _H8300_BITOPS_H */
#ifndef __ASM_H8300_BITS_PER_LONG
#define __ASM_H8300_BITS_PER_LONG
#include <asm-generic/bitsperlong.h>
#if !defined(__ASSEMBLY__)
/* h8300-unknown-linux required long */
#define __kernel_size_t __kernel_size_t
typedef unsigned long __kernel_size_t;
typedef long __kernel_ssize_t;
typedef long __kernel_ptrdiff_t;
#endif
#endif /* __ASM_H8300_BITS_PER_LONG */
#ifndef _H8300_BUG_H
#define _H8300_BUG_H
/* always true */
#define is_valid_bugaddr(addr) (1)
#include <asm-generic/bug.h>
struct pt_regs;
extern void die(const char *str, struct pt_regs *fp, unsigned long err);
#endif
#ifndef __H8300_BYTEORDER_H__
#define __H8300_BYTEORDER_H__
#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
#include <linux/byteorder/big_endian.h>
#endif
#ifndef __ARCH_H8300_CACHE_H
#define __ARCH_H8300_CACHE_H
/* bytes per L1 cache line */
#define L1_CACHE_SHIFT 2
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
#define __cacheline_aligned
#define ____cacheline_aligned
#endif
#ifndef __ARCH_H8300_CMPXCHG__
#define __ARCH_H8300_CMPXCHG__
#include <linux/irqflags.h>
#define xchg(ptr, x) \
((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), \
sizeof(*(ptr))))
struct __xchg_dummy { unsigned long a[100]; };
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
static inline unsigned long __xchg(unsigned long x,
volatile void *ptr, int size)
{
unsigned long tmp, flags;
local_irq_save(flags);
switch (size) {
case 1:
__asm__ __volatile__
("mov.b %2,%0\n\t"
"mov.b %1,%2"
: "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
break;
case 2:
__asm__ __volatile__
("mov.w %2,%0\n\t"
"mov.w %1,%2"
: "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
break;
case 4:
__asm__ __volatile__
("mov.l %2,%0\n\t"
"mov.l %1,%2"
: "=&r" (tmp) : "r" (x), "m" (*__xg(ptr)));
break;
default:
tmp = 0;
}
local_irq_restore(flags);
return tmp;
}
#include <asm-generic/cmpxchg-local.h>
/*
* cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
* them available.
*/
#define cmpxchg_local(ptr, o, n) \
((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), \
(unsigned long)(o), \
(unsigned long)(n), \
sizeof(*(ptr))))
#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
#ifndef CONFIG_SMP
#include <asm-generic/cmpxchg.h>
#endif
#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
#endif /* __ARCH_H8300_CMPXCHG__ */
#ifndef _H8300_DMA_MAPPING_H
#define _H8300_DMA_MAPPING_H
#include <asm-generic/dma-coherent.h>
extern struct dma_map_ops h8300_dma_map_ops;
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{
return &h8300_dma_map_ops;
}
#include <asm-generic/dma-mapping-common.h>
static inline int dma_supported(struct device *dev, u64 mask)
{
return 0;
}
static inline int dma_set_mask(struct device *dev, u64 mask)
{
return 0;
}
#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_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL)
static inline void *dma_alloc_attrs(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag,
struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
void *memory;
memory = ops->alloc(dev, size, dma_handle, flag, attrs);
return memory;
}
#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL)
static inline void dma_free_attrs(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle,
struct dma_attrs *attrs)
{
struct dma_map_ops *ops = get_dma_ops(dev);
ops->free(dev, size, cpu_addr, dma_handle, attrs);
}
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
{
return 0;
}
#endif
#ifndef __ASM_H8300_ELF_H
#define __ASM_H8300_ELF_H
/*
* ELF register definitions..
*/
#include <asm/ptrace.h>
#include <asm/user.h>
typedef unsigned long elf_greg_t;
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
typedef unsigned long elf_fpregset_t;
/*
* This is used to ensure we don't load something for the wrong architecture.
*/
#define elf_check_arch(x) ((x)->e_machine == EM_H8_300)
/*
* These are used to set parameters in the core dumps.
*/
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
#define ELF_ARCH EM_H8_300
#if defined(CONFIG_CPU_H8300H)
#define ELF_CORE_EFLAGS 0x810000
#endif
#if defined(CONFIG_CPU_H8S)
#define ELF_CORE_EFLAGS 0x820000
#endif
#define ELF_PLAT_INIT(_r) do { (_r)->er1 = 0; } while (0)
#define ELF_EXEC_PAGESIZE 4096
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
use of this is to invoke "./ld.so someprog" to test out a new version of
the loader. We need to make sure that it is out of the way of the program
that it will "exec", and that there is sufficient room for the brk. */
#define ELF_ET_DYN_BASE 0xD0000000UL
/* This yields a mask that user programs can use to figure out what
instruction set this cpu supports. */
#define ELF_HWCAP (0)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo. */
#define ELF_PLATFORM (NULL)
#define R_H8_NONE 0
#define R_H8_DIR32 1
#define R_H8_DIR32_28 2
#define R_H8_DIR32_24 3
#define R_H8_DIR32_16 4
#define R_H8_DIR32U 6
#define R_H8_DIR32U_28 7
#define R_H8_DIR32U_24 8
#define R_H8_DIR32U_20 9
#define R_H8_DIR32U_16 10
#define R_H8_DIR24 11
#define R_H8_DIR24_20 12
#define R_H8_DIR24_16 13
#define R_H8_DIR24U 14
#define R_H8_DIR24U_20 15
#define R_H8_DIR24U_16 16
#define R_H8_DIR16 17
#define R_H8_DIR16U 18
#define R_H8_DIR16S_32 19
#define R_H8_DIR16S_28 20
#define R_H8_DIR16S_24 21
#define R_H8_DIR16S_20 22
#define R_H8_DIR16S 23
#define R_H8_DIR8 24
#define R_H8_DIR8U 25
#define R_H8_DIR8Z_32 26
#define R_H8_DIR8Z_28 27
#define R_H8_DIR8Z_24 28
#define R_H8_DIR8Z_20 29
#define R_H8_DIR8Z_16 30
#define R_H8_PCREL16 31
#define R_H8_PCREL8 32
#define R_H8_BPOS 33
#define R_H8_PCREL32 34
#define R_H8_GOT32O 35
#define R_H8_GOT16O 36
#define R_H8_DIR16A8 59
#define R_H8_DIR16R8 60
#define R_H8_DIR24A8 61
#define R_H8_DIR24R8 62
#define R_H8_DIR32A16 63
#define R_H8_ABS32 65
#define R_H8_ABS32A16 127
#endif
/*
* arch/h8300/asm/include/flat.h -- uClinux flat-format executables
*/
#ifndef __H8300_FLAT_H__
#define __H8300_FLAT_H__
#define flat_argvp_envp_on_stack() 1
#define flat_old_ram_flag(flags) 1
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_set_persistent(relval, p) 0
/*
* on the H8 a couple of the relocations have an instruction in the
* top byte. As there can only be 24bits of address space, we just
* always preserve that 8bits at the top, when it isn't an instruction
* is is 0 (davidm@snapgear.com)
*/
#define flat_get_relocate_addr(rel) (rel & ~0x00000001)
#define flat_get_addr_from_rp(rp, relval, flags, persistent) \
({(void)persistent; \
get_unaligned(rp) & (((flags) & FLAT_FLAG_GOTPIC) ? \
0xffffffff : 0x00ffffff); })
#define flat_put_addr_at_rp(rp, addr, rel) \
put_unaligned(((*(char *)(rp)) << 24) | ((addr) & 0x00ffffff), (rp))
#endif /* __H8300_FLAT_H__ */
#ifndef _H8300_IO_H
#define _H8300_IO_H
#ifdef __KERNEL__
#include <asm-generic/io.h>
/* H8/300 internal I/O functions */
static inline unsigned char ctrl_inb(unsigned long addr)
{
return *(volatile unsigned char *)addr;
}
static inline unsigned short ctrl_inw(unsigned long addr)
{
return *(volatile unsigned short *)addr;
}
static inline unsigned long ctrl_inl(unsigned long addr)
{
return *(volatile unsigned long *)addr;
}
static inline void ctrl_outb(unsigned char b, unsigned long addr)
{
*(volatile unsigned char *)addr = b;
}
static inline void ctrl_outw(unsigned short b, unsigned long addr)
{
*(volatile unsigned short *)addr = b;
}
static inline void ctrl_outl(unsigned long b, unsigned long addr)
{
*(volatile unsigned long *)addr = b;
}
static inline void ctrl_bclr(int b, unsigned long addr)
{
if (__builtin_constant_p(b))
__asm__("bclr %1,%0" : : "WU"(addr), "i"(b));
else
__asm__("bclr %w1,%0" : : "WU"(addr), "r"(b));
}
static inline void ctrl_bset(int b, unsigned long addr)
{
if (__builtin_constant_p(b))
__asm__("bset %1,%0" : : "WU"(addr), "i"(b));
else
__asm__("bset %w1,%0" : : "WU"(addr), "r"(b));
}
#endif /* __KERNEL__ */
#endif /* _H8300_IO_H */
#ifndef _H8300_IRQ_H_
#define _H8300_IRQ_H_
#include <linux/irqchip.h>
#if defined(CONFIG_CPU_H8300H)
#define NR_IRQS 64
#define IRQ_CHIP h8300h_irq_chip
#define EXT_IRQ0 12
#define EXT_IRQS 6
#elif defined(CONFIG_CPU_H8S)
#define NR_IRQS 128
#define IRQ_CHIP h8s_irq_chip
#define EXT_IRQ0 16
#define EXT_IRQS 16
#endif
static inline int irq_canonicalize(int irq)
{
return irq;
}
void h8300_init_ipr(void);
extern struct irq_chip h8300h_irq_chip;
extern struct irq_chip h8s_irq_chip;
#endif /* _H8300_IRQ_H_ */
#ifndef _H8300_IRQFLAGS_H
#define _H8300_IRQFLAGS_H
#ifdef CONFIG_CPU_H8300H
typedef unsigned char h8300flags;
static inline h8300flags arch_local_save_flags(void)
{
h8300flags flags;
__asm__ volatile ("stc ccr,%w0" : "=r" (flags));
return flags;
}
static inline void arch_local_irq_disable(void)
{
__asm__ volatile ("orc #0xc0,ccr");
}
static inline void arch_local_irq_enable(void)
{
__asm__ volatile ("andc #0x3f,ccr");
}
static inline h8300flags arch_local_irq_save(void)
{
h8300flags flags;
__asm__ volatile ("stc ccr,%w0\n\t"
"orc #0xc0,ccr" : "=r" (flags));
return flags;
}
static inline void arch_local_irq_restore(h8300flags flags)
{
__asm__ volatile ("ldc %w0,ccr" : : "r" (flags) : "cc");
}
static inline int arch_irqs_disabled_flags(unsigned long flags)
{
return (flags & 0xc0) == 0xc0;
}
#endif
#ifdef CONFIG_CPU_H8S
typedef unsigned short h8300flags;
static inline h8300flags arch_local_save_flags(void)
{
h8300flags flags;
__asm__ volatile ("stc ccr,%w0\n\tstc exr,%x0" : "=r" (flags));
return flags;
}
static inline void arch_local_irq_disable(void)
{
__asm__ volatile ("orc #0x80,ccr\n\t");
}
static inline void arch_local_irq_enable(void)
{
__asm__ volatile ("andc #0x7f,ccr\n\t"
"andc #0xf0,exr\n\t");
}
static inline h8300flags arch_local_irq_save(void)
{
h8300flags flags;
__asm__ volatile ("stc ccr,%w0\n\t"
"stc exr,%x0\n\t"
"orc #0x80,ccr\n\t"
: "=r" (flags));
return flags;
}
static inline void arch_local_irq_restore(h8300flags flags)
{
__asm__ volatile ("ldc %w0,ccr\n\t"
"ldc %x0,exr"
: : "r" (flags) : "cc");
}
static inline int arch_irqs_disabled_flags(h8300flags flags)
{
return (flags & 0x0080) == 0x0080;
}
#endif
static inline int arch_irqs_disabled(void)
{
return arch_irqs_disabled_flags(arch_local_save_flags());
}
#endif /* _H8300_IRQFLAGS_H */
/*
* Machine dependent access functions for RTC registers.
*/
#ifndef _H8300_MC146818RTC_H
#define _H8300_MC146818RTC_H
/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
#endif /* _H8300_MC146818RTC_H */
/*
* Pull in the generic implementation for the mutex fastpath.
*
* TODO: implement optimized primitives instead, or leave the generic
* implementation in place, or pick the atomic_xchg() based generic
* implementation. (see asm-generic/mutex-xchg.h for details)
*/
#include <asm-generic/mutex-dec.h>
#ifndef _H8300_PAGE_H
#define _H8300_PAGE_H
#include <asm-generic/page.h>
#include <linux/types.h>
#define MAP_NR(addr) (((uintptr_t)(addr)-PAGE_OFFSET) >> PAGE_SHIFT)
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
#ifndef __ASSEMBLY__
extern unsigned long rom_length;
extern unsigned long memory_start;
extern unsigned long memory_end;
extern unsigned long _ramend;
#endif
#endif
#define PAGE_OFFSET_RAW 0x00000000
#ifndef _ASM_H8300_PCI_H
#define _ASM_H8300_PCI_H
/*
* asm-h8300/pci.h - H8/300 specific PCI declarations.
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#define pcibios_assign_all_busses() 0
static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
#define PCI_DMA_BUS_IS_PHYS (1)
#endif /* _ASM_H8300_PCI_H */
#ifndef _H8300_PGTABLE_H
#define _H8300_PGTABLE_H
#include <asm-generic/pgtable-nopud.h>
#include <asm-generic/pgtable.h>
#define pgtable_cache_init() do { } while (0)
extern void paging_init(void);
#define PAGE_NONE __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_SHARED __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_COPY __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_READONLY __pgprot(0) /* these mean nothing to NO_MM */
#define PAGE_KERNEL __pgprot(0) /* these mean nothing to NO_MM */
#define __swp_type(x) (0)
#define __swp_offset(x) (0)
#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) })
#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
#define kern_addr_valid(addr) (1)
#define pgprot_writecombine(prot) (prot)
#define pgprot_noncached pgprot_writecombine
static inline int pte_file(pte_t pte) { return 0; }
#define swapper_pg_dir ((pgd_t *) 0)
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
#define ZERO_PAGE(vaddr) (virt_to_page(0))
/*
* These would be in other places but having them here reduces the diffs.
*/
extern unsigned int kobjsize(const void *objp);
extern int is_in_rom(unsigned long);
/*
* No page table caches to initialise
*/
#define pgtable_cache_init() do { } while (0)
/*
* All 32bit addresses are effectively valid for vmalloc...
* Sort of meaningless for non-VM targets.
*/
#define VMALLOC_START 0
#define VMALLOC_END 0xffffffff
#define arch_enter_lazy_cpu_mode() do {} while (0)
#endif /* _H8300_PGTABLE_H */
/*
* include/asm-h8300/processor.h
*
* Copyright (C) 2002 Yoshinori Sato
*
* Based on: linux/asm-m68nommu/processor.h
*
* Copyright (C) 1995 Hamish Macdonald
*/
#ifndef __ASM_H8300_PROCESSOR_H
#define __ASM_H8300_PROCESSOR_H
/*
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
#define current_text_addr() ({ __label__ _l; _l: &&_l; })
#include <linux/compiler.h>
#include <asm/segment.h>
#include <asm/ptrace.h>
#include <asm/current.h>
static inline unsigned long rdusp(void)
{
extern unsigned int _sw_usp;
return _sw_usp;
}
static inline void wrusp(unsigned long usp)
{
extern unsigned int _sw_usp;
_sw_usp = usp;
}
/*
* User space process size: 3.75GB. This is hardcoded into a few places,
* so don't change it unless you know what you are doing.
*/
#define TASK_SIZE (0xFFFFFFFFUL)
#ifdef __KERNEL__
#define STACK_TOP TASK_SIZE
#define STACK_TOP_MAX STACK_TOP
#endif
/*
* This decides where the kernel will search for a free chunk of vm
* space during mmap's. We won't be using it
*/
#define TASK_UNMAPPED_BASE 0
struct thread_struct {
unsigned long ksp; /* kernel stack pointer */
unsigned long usp; /* user stack pointer */
unsigned long ccr; /* saved status register */
unsigned long esp0; /* points to SR of stack frame */
struct {
unsigned short *addr;
unsigned short inst;
} breakinfo;
};
#define INIT_THREAD { \
.ksp = sizeof(init_stack) + (unsigned long)init_stack, \
.usp = 0, \
.ccr = PS_S, \
.esp0 = 0, \
.breakinfo = { \
.addr = (unsigned short *)-1, \
.inst = 0 \
} \
}
/*
* Do necessary setup to start up a newly executed thread.
*
* pass the data segment into user programs if it exists,
* it can't hurt anything as far as I can tell
*/
#if defined(CONFIG_CPU_H8300H)
#define start_thread(_regs, _pc, _usp) \
do { \
(_regs)->pc = (_pc); \
(_regs)->ccr = 0x00; /* clear all flags */ \
(_regs)->er5 = current->mm->start_data; /* GOT base */ \
(_regs)->sp = ((unsigned long)(_usp)) - sizeof(unsigned long) * 3; \
} while (0)
#endif
#if defined(CONFIG_CPU_H8S)
#define start_thread(_regs, _pc, _usp) \
do { \
(_regs)->pc = (_pc); \
(_regs)->ccr = 0x00; /* clear kernel flag */ \
(_regs)->exr = 0x78; /* enable all interrupts */ \
(_regs)->er5 = current->mm->start_data; /* GOT base */ \
/* 14 = space for retaddr(4), vector(4), er0(4) and exr(2) on stack */ \
(_regs)->sp = ((unsigned long)(_usp)) - 14; \
} while (0)
#endif
/* Forward declaration, a strange C thing */
struct task_struct;
/* Free all resources held by a thread. */
static inline void release_thread(struct task_struct *dead_task)
{
}
/*
* Free current thread data structures etc..
*/
static inline void exit_thread(void)
{
}
/*
* Return saved PC of a blocked thread.
*/
unsigned long thread_saved_pc(struct task_struct *tsk);
unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) \
({ \
unsigned long eip = 0; \
if ((tsk)->thread.esp0 > PAGE_SIZE && \
MAP_NR((tsk)->thread.esp0) < max_mapnr) \
eip = ((struct pt_regs *) (tsk)->thread.esp0)->pc; \
eip; })
#define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp)
#define cpu_relax() barrier()
#define cpu_relax_lowlatency() cpu_relax()
#define HARD_RESET_NOW() ({ \
local_irq_disable(); \
asm("jmp @@0"); \
})
#endif
#ifndef _H8300_PTRACE_H
#define _H8300_PTRACE_H
#include <uapi/asm/ptrace.h>
#ifndef __ASSEMBLY__
#ifndef PS_S
#define PS_S (0x10)
#endif
#if defined(CONFIG_CPU_H8300H)
#define H8300_REGS_NO 11
#endif
#if defined(CONFIG_CPU_H8S)
#define H8300_REGS_NO 12
#endif
#define arch_has_single_step() (1)
#define user_mode(regs) (!((regs)->ccr & PS_S))
#define instruction_pointer(regs) ((regs)->pc)
#define profile_pc(regs) instruction_pointer(regs)
#define user_stack_pointer(regs) ((regs)->sp)
#define current_pt_regs() ((struct pt_regs *) \
(THREAD_SIZE + (unsigned long)current_thread_info()) - 1)
#define signal_pt_regs() ((struct pt_regs *)current->thread.esp0)
#define current_user_stack_pointer() rdusp()
#define task_pt_regs(task) \
((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
extern long h8300_get_reg(struct task_struct *task, int regno);
extern int h8300_put_reg(struct task_struct *task, int regno,
unsigned long data);
#endif /* __ASSEMBLY__ */
#endif /* _H8300_PTRACE_H */
#ifndef _H8300_SEGMENT_H
#define _H8300_SEGMENT_H
/* define constants */
#define USER_DATA (1)
#ifndef __USER_DS
#define __USER_DS (USER_DATA)
#endif
#define USER_PROGRAM (2)
#define SUPER_DATA (3)
#ifndef __KERNEL_DS
#define __KERNEL_DS (SUPER_DATA)
#endif
#define SUPER_PROGRAM (4)
#ifndef __ASSEMBLY__
typedef struct {
unsigned long seg;
} mm_segment_t;
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define USER_DS MAKE_MM_SEG(__USER_DS)
#define KERNEL_DS MAKE_MM_SEG(__KERNEL_DS)
/*
* Get/set the SFC/DFC registers for MOVES instructions
*/
static inline mm_segment_t get_fs(void)
{
return USER_DS;
}
static inline mm_segment_t get_ds(void)
{
/* return the supervisor data space code */
return KERNEL_DS;
}
#define segment_eq(a, b) ((a).seg == (b).seg)
#endif /* __ASSEMBLY__ */
#endif /* _H8300_SEGMENT_H */
#ifndef _H8300_SIGNAL_H
#define _H8300_SIGNAL_H
#include <uapi/asm/signal.h>
/* Most things should be clean enough to redefine this at will, if care
is taken to make libc match. */
#define _NSIG 64
#define _NSIG_BPW 32
#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
typedef unsigned long old_sigset_t; /* at least 32 bits */
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t;
#define __ARCH_HAS_SA_RESTORER
#include <asm/sigcontext.h>
#endif /* _H8300_SIGNAL_H */
/* nothing required here yet */
#ifndef _H8300_STRING_H_
#define _H8300_STRING_H_
#ifdef __KERNEL__ /* only set these up for kernel code */
#include <asm/setup.h>
#include <asm/page.h>
#define __HAVE_ARCH_MEMSET
extern void *memset(void *s, int c, size_t count);
#define __HAVE_ARCH_MEMCPY
extern void *memcpy(void *d, const void *s, size_t count);
#endif /* KERNEL */
#endif
#ifndef _H8300_SWITCH_TO_H
#define _H8300_SWITCH_TO_H
/*
* switch_to(n) should switch tasks to task ptr, first checking that
* ptr isn't the current task, in which case it does nothing. This
* also clears the TS-flag if the task we switched to has used the
* math co-processor latest.
*/
/*
* switch_to() saves the extra registers, that are not saved
* automatically by SAVE_SWITCH_STACK in resume(), ie. d0-d5 and
* a0-a1. Some of these are used by schedule() and its predecessors
* and so we might get see unexpected behaviors when a task returns
* with unexpected register values.
*
* syscall stores these registers itself and none of them are used
* by syscall after the function in the syscall has been called.
*
* Beware that resume now expects *next to be in d1 and the offset of
* tss to be in a1. This saves a few instructions as we no longer have
* to push them onto the stack and read them back right after.
*
* 02/17/96 - Jes Sorensen (jds@kom.auc.dk)
*
* Changed 96/09/19 by Andreas Schwab
* pass prev in a0, next in a1, offset of tss in d1, and whether
* the mm structures are shared in d2 (to avoid atc flushing).
*
* H8/300 Porting 2002/09/04 Yoshinori Sato
*/
asmlinkage void resume(void);
#define switch_to(prev, next, last) \
do { \
void *_last; \
__asm__ __volatile__( \
"mov.l %1, er0\n\t" \
"mov.l %2, er1\n\t" \
"mov.l %3, er2\n\t" \
"jsr @_resume\n\t" \
"mov.l er2,%0\n\t" \
: "=r" (_last) \
: "r" (&(prev->thread)), \
"r" (&(next->thread)), \
"g" (prev) \
: "cc", "er0", "er1", "er2", "er3"); \
(last) = _last; \
} while (0)
#endif /* _H8300_SWITCH_TO_H */
#ifndef __ASM_H8300_SYSCALLS_32_H
#define __ASM_H8300_SYSCALLS_32_H
#ifdef __KERNEL__
#include <linux/compiler.h>
#include <linux/linkage.h>
#include <linux/types.h>
#include <linux/ptrace.h>
static inline int
syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
{
return regs->orig_er0;
}
static inline void
syscall_get_arguments(struct task_struct *task, struct pt_regs *regs,
unsigned int i, unsigned int n, unsigned long *args)
{
BUG_ON(i + n > 6);
while (n > 0) {
switch (i) {
case 0:
*args++ = regs->er1;
break;
case 1:
*args++ = regs->er2;
break;
case 2:
*args++ = regs->er3;
break;
case 3:
*args++ = regs->er4;
break;
case 4:
*args++ = regs->er5;
break;
case 5:
*args++ = regs->er6;
break;
}
i++;
n--;
}
}
/* Misc syscall related bits */
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs);
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs);
#endif /* __KERNEL__ */
#endif /* __ASM_H8300_SYSCALLS_32_H */
/* thread_info.h: h8300 low-level thread information
* adapted from the i386 and PPC versions by Yoshinori Sato <ysato@users.sourceforge.jp>
*
* Copyright (C) 2002 David Howells (dhowells@redhat.com)
* - Incorporating suggestions made by Linus Torvalds and Dave Miller
*/
#ifndef _ASM_THREAD_INFO_H
#define _ASM_THREAD_INFO_H
#include <asm/page.h>
#include <asm/segment.h>
#ifdef __KERNEL__
#ifndef __ASSEMBLY__
/*
* low level task data.
* If you change this, change the TI_* offsets below to match.
*/
struct thread_info {
struct task_struct *task; /* main task structure */
unsigned long flags; /* low level flags */
int cpu; /* cpu we're on */
int preempt_count; /* 0 => preemptable, <0 => BUG */
mm_segment_t addr_limit;
struct restart_block restart_block;
};
/*
* macros/functions for gaining access to the thread information structure
*/
#define INIT_THREAD_INFO(tsk) \
{ \
.task = &tsk, \
.flags = 0, \
.cpu = 0, \
.preempt_count = INIT_PREEMPT_COUNT, \
.addr_limit = KERNEL_DS, \
.restart_block = { \
.fn = do_no_restart_syscall, \
}, \
}
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
/*
* Size of kernel stack for each process. This must be a power of 2...
*/
#define THREAD_SIZE_ORDER 1
#define THREAD_SIZE 8192 /* 2 pages */
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
__asm__("mov.l sp, %0\n\t"
"and.w %1, %T0"
: "=&r"(ti)
: "i" (~(THREAD_SIZE-1) & 0xffff));
return ti;
}
#endif /* __ASSEMBLY__ */
/*
* thread information flag bit numbers
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
#define TIF_SIGPENDING 1 /* signal pending */
#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
#define TIF_SINGLESTEP 3 /* singlestepping active */
#define TIF_MEMDIE 4 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 6 /* callback before returning to user */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */
#define TIF_POLLING_NRFLAG 9 /* true if poll_idle() is polling TIF_NEED_RESCHED */
/* as above, but as bit values */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
/* work to do in syscall trace */
#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
_TIF_SYSCALL_AUDIT | _TIF_SYSCALL_TRACEPOINT)
/* 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_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))
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
#ifndef __H8300_TLB_H__
#define __H8300_TLB_H__
#define tlb_flush(tlb) do { } while (0)
#include <asm-generic/tlb.h>
#endif
/*
* linux/include/asm-h8300/traps.h
*
* Copyright (C) 2003 Yoshinori Sato <ysato@users.sourceforge.jp>
*
* 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.
*/
#ifndef _H8300_TRAPS_H
#define _H8300_TRAPS_H
extern void _system_call(void);
extern void _interrupt_entry(void);
extern void _trace_break(void);
extern void _nmi(void);
extern void _interrupt_entry(void);
extern unsigned long *_interrupt_redirect_table;
#define JMP_OP 0x5a000000
#define JSR_OP 0x5e000000
#define VECTOR(address) ((JMP_OP)|((unsigned long)address))
#define REDIRECT(address) ((JSR_OP)|((unsigned long)address))
#define CPU_VECTOR ((unsigned long *)0x000000)
#define ADDR_MASK (0xffffff)
#define TRACE_VEC 5
#define TRAP0_VEC 8
#define TRAP1_VEC 9
#define TRAP2_VEC 10
#define TRAP3_VEC 11
extern char _start, _etext;
#define check_kernel_text(addr) \
((addr >= (unsigned long)(&_start)) && \
(addr < (unsigned long)(&_etext)))
#endif /* _H8300_TRAPS_H */
#ifndef _H8300_USER_H
#define _H8300_USER_H
#include <asm/page.h>
/* Core file format: The core file is written in such a way that gdb
can understand it and provide useful information to the user (under
linux we use the 'trad-core' bfd). There are quite a number of
obstacles to being able to view the contents of the floating point
registers, and until these are solved you will not be able to view the
contents of them. Actually, you can read in the core file and look at
the contents of the user struct to find out what the floating point
registers contain.
The actual file contents are as follows:
UPAGE: 1 page consisting of a user struct that tells gdb what is present
in the file. Directly after this is a copy of the task_struct, which
is currently not used by gdb, but it may come in useful at some point.
All of the registers are stored as part of the upage. The upage should
always be only one page.
DATA: The data area is stored. We use current->end_text to
current->brk to pick up all of the user variables, plus any memory
that may have been malloced. No attempt is made to determine if a page
is demand-zero or if a page is totally unused, we just cover the entire
range. All of the addresses are rounded in such a way that an integral
number of pages is written.
STACK: We need the stack information in order to get a meaningful
backtrace. We need to write the data from (esp) to
current->start_stack, so we round each of these off in order to be able
to write an integer number of pages.
The minimum core file size is 3 pages, or 12288 bytes.
*/
/* This is the old layout of "struct pt_regs" as of Linux 1.x, and
is still the layout used by user (the new pt_regs doesn't have
all registers). */
struct user_regs_struct {
long er1, er2, er3, er4, er5, er6;
long er0;
long usp;
long orig_er0;
long ccr;
long pc;
};
/* When the kernel dumps core, it starts by dumping the user struct -
this will be used by gdb to figure out where the data and stack segments
are within the file, and what virtual addresses to use. */
struct user {
/* We start with the registers, to mimic the way that "memory" is returned
from the ptrace(3,...) function. */
struct user_regs_struct regs; /* Where the registers are actually stored */
/* ptrace does not yet supply these. Someday.... */
/* The rest of this junk is to help gdb figure out what goes where */
unsigned long int u_tsize; /* Text segment size (pages). */
unsigned long int u_dsize; /* Data segment size (pages). */
unsigned long int u_ssize; /* Stack segment size (pages). */
unsigned long start_code; /* Starting virtual address of text. */
unsigned long start_stack; /* Starting virtual address of stack area.
This is actually the bottom of the stack,
the top of the stack is always found in the
esp register. */
long int signal; /* Signal that caused the core dump. */
int reserved; /* No longer used */
unsigned long u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
unsigned long magic; /* To uniquely identify a core file */
char u_comm[32]; /* User command that was responsible */
};
#define NBPG PAGE_SIZE
#define UPAGES 1
#define HOST_TEXT_START_ADDR (u.start_code)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
#endif
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
header-y += auxvec.h
header-y += bitsperlong.h
header-y += errno.h
header-y += fcntl.h
header-y += ioctl.h
header-y += ioctls.h
header-y += ipcbuf.h
header-y += kvm_para.h
header-y += mman.h
header-y += msgbuf.h
header-y += param.h
header-y += poll.h
header-y += posix_types.h
header-y += resource.h
header-y += sembuf.h
header-y += setup.h
header-y += shmbuf.h
header-y += siginfo.h
header-y += socket.h
header-y += sockios.h
header-y += stat.h
header-y += statfs.h
header-y += swab.h
header-y += termbits.h
header-y += termios.h
header-y += types.h
header-y += unistd.h
#ifndef _H8300_BYTEORDER_H
#define _H8300_BYTEORDER_H
#include <linux/byteorder/big_endian.h>
#endif /* _H8300_BYTEORDER_H */
#ifndef _UAPI_H8300_PTRACE_H
#define _UAPI_H8300_PTRACE_H
#ifndef __ASSEMBLY__
#define PT_ER1 0
#define PT_ER2 1
#define PT_ER3 2
#define PT_ER4 3
#define PT_ER5 4
#define PT_ER6 5
#define PT_ER0 6
#define PT_USP 7
#define PT_ORIG_ER0 8
#define PT_CCR 9
#define PT_PC 10
#define PT_EXR 11
/* this struct defines the way the registers are stored on the
stack during a system call. */
struct pt_regs {
long retpc;
long er4;
long er5;
long er6;
long er3;
long er2;
long er1;
long orig_er0;
long sp;
unsigned short ccr;
long er0;
long vector;
#if defined(__H8300S__)
unsigned short exr;
#endif
unsigned long pc;
} __attribute__((aligned(2), packed));
#endif /* __ASSEMBLY__ */
#endif /* _UAPI_H8300_PTRACE_H */
#ifndef _ASM_H8300_SIGCONTEXT_H
#define _ASM_H8300_SIGCONTEXT_H
struct sigcontext {
unsigned long sc_mask; /* old sigmask */
unsigned long sc_usp; /* old user stack pointer */
unsigned long sc_er0;
unsigned long sc_er1;
unsigned long sc_er2;
unsigned long sc_er3;
unsigned long sc_er4;
unsigned long sc_er5;
unsigned long sc_er6;
unsigned short sc_ccr;
unsigned long sc_pc;
};
#endif
#ifndef _UAPI_H8300_SIGNAL_H
#define _UAPI_H8300_SIGNAL_H
#include <linux/types.h>
/* Avoid too many header ordering problems. */
struct siginfo;
#ifndef __KERNEL__
/* Here we must cater to libcs that poke about in kernel headers. */
#define NSIG 32
typedef unsigned long sigset_t;
#endif /* __KERNEL__ */
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13
#define SIGALRM 14
#define SIGTERM 15
#define SIGSTKFLT 16
#define SIGCHLD 17
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
#define SIGXCPU 24
#define SIGXFSZ 25
#define SIGVTALRM 26
#define SIGPROF 27
#define SIGWINCH 28
#define SIGIO 29
#define SIGPOLL SIGIO
/*
#define SIGLOST 29
*/
#define SIGPWR 30
#define SIGSYS 31
#define SIGUNUSED 31
/* These should not be considered constants from userland. */
#define SIGRTMIN 32
#define SIGRTMAX _NSIG
/*
* SA_FLAGS values:
*
* SA_ONSTACK indicates that a registered stack_t will be used.
* SA_RESTART flag to get restarting signals (which were the default long ago)
* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
* SA_RESETHAND clears the handler when the signal is delivered.
* SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
* SA_NODEFER prevents the current signal from being masked in the handler.
*
* SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
* Unix names RESETHAND and NODEFER respectively.
*/
#define SA_NOCLDSTOP 0x00000001
#define SA_NOCLDWAIT 0x00000002 /* not supported yet */
#define SA_SIGINFO 0x00000004
#define SA_ONSTACK 0x08000000
#define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000
#define SA_NOMASK SA_NODEFER
#define SA_ONESHOT SA_RESETHAND
#define SA_RESTORER 0x04000000
#define MINSIGSTKSZ 2048
#define SIGSTKSZ 8192
#include <asm-generic/signal-defs.h>
#ifndef __KERNEL__
/* Here we must cater to libcs that poke about in kernel headers. */
struct sigaction {
union {
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo *, void *);
} _u;
sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
};
#define sa_handler _u._sa_handler
#define sa_sigaction _u._sa_sigaction
#endif /* __KERNEL__ */
typedef struct sigaltstack {
void *ss_sp;
int ss_flags;
size_t ss_size;
} stack_t;
#endif /* _UAPI_H8300_SIGNAL_H */
#define __ARCH_NOMMU
#include <asm-generic/unistd.h>
#
# Makefile for the linux kernel.
#
extra-y := vmlinux.lds
obj-y := process.o traps.o ptrace.o \
signal.o setup.o syscalls.o \
irq.o entry.o dma.o
obj-$(CONFIG_ROMKERNEL) += head_rom.o
obj-$(CONFIG_RAMKERNEL) += head_ram.o
obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o
obj-$(CONFIG_H8300H_SIM) += sim-console.o
obj-$(CONFIG_H8S_SIM) += sim-console.o
obj-$(CONFIG_CPU_H8300H) += ptrace_h.o
obj-$(CONFIG_CPU_H8S) += ptrace_s.o
/*
* This program is used to generate definitions needed by
* assembly language modules.
*
* We use the technique used in the OSF Mach kernel code:
* generate asm statements containing #defines,
* compile this file to assembler, and then extract the
* #defines from the assembly-language output.
*/
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
#include <linux/kbuild.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
int main(void)
{
/* offsets into the task struct */
OFFSET(TASK_STATE, task_struct, state);
OFFSET(TASK_FLAGS, task_struct, flags);
OFFSET(TASK_PTRACE, task_struct, ptrace);
OFFSET(TASK_BLOCKED, task_struct, blocked);
OFFSET(TASK_THREAD, task_struct, thread);
OFFSET(TASK_THREAD_INFO, task_struct, stack);
OFFSET(TASK_MM, task_struct, mm);
OFFSET(TASK_ACTIVE_MM, task_struct, active_mm);
/* offsets into the irq_cpustat_t struct */
DEFINE(CPUSTAT_SOFTIRQ_PENDING, offsetof(irq_cpustat_t,
__softirq_pending));
/* offsets into the thread struct */
OFFSET(THREAD_KSP, thread_struct, ksp);
OFFSET(THREAD_USP, thread_struct, usp);
OFFSET(THREAD_CCR, thread_struct, ccr);
/* offsets into the pt_regs struct */
DEFINE(LER0, offsetof(struct pt_regs, er0) - sizeof(long));
DEFINE(LER1, offsetof(struct pt_regs, er1) - sizeof(long));
DEFINE(LER2, offsetof(struct pt_regs, er2) - sizeof(long));
DEFINE(LER3, offsetof(struct pt_regs, er3) - sizeof(long));
DEFINE(LER4, offsetof(struct pt_regs, er4) - sizeof(long));
DEFINE(LER5, offsetof(struct pt_regs, er5) - sizeof(long));
DEFINE(LER6, offsetof(struct pt_regs, er6) - sizeof(long));
DEFINE(LORIG, offsetof(struct pt_regs, orig_er0) - sizeof(long));
DEFINE(LSP, offsetof(struct pt_regs, sp) - sizeof(long));
DEFINE(LCCR, offsetof(struct pt_regs, ccr) - sizeof(long));
DEFINE(LVEC, offsetof(struct pt_regs, vector) - sizeof(long));
#if defined(CONFIG_CPU_H8S)
DEFINE(LEXR, offsetof(struct pt_regs, exr) - sizeof(long));
#endif
DEFINE(LRET, offsetof(struct pt_regs, pc) - sizeof(long));
DEFINE(PT_PTRACED, PT_PTRACED);
/* offsets in thread_info structure */
OFFSET(TI_TASK, thread_info, task);
OFFSET(TI_FLAGS, thread_info, flags);
OFFSET(TI_CPU, thread_info, cpu);
OFFSET(TI_PRE, thread_info, preempt_count);
return 0;
}
/*
* 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/kernel.h>
#include <linux/scatterlist.h>
#include <linux/module.h>
#include <asm/pgalloc.h>
static void *dma_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp,
struct dma_attrs *attrs)
{
void *ret;
/* ignore region specifiers */
gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
if (dev == NULL || (*dev->dma_mask < 0xffffffff))
gfp |= GFP_DMA;
ret = (void *)__get_free_pages(gfp, get_order(size));
if (ret != NULL) {
memset(ret, 0, size);
*dma_handle = virt_to_phys(ret);
}
return ret;
}
static void dma_free(struct device *dev, size_t size,
void *vaddr, dma_addr_t dma_handle,
struct dma_attrs *attrs)
{
free_pages((unsigned long)vaddr, get_order(size));
}
static dma_addr_t map_page(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction,
struct dma_attrs *attrs)
{
return page_to_phys(page) + offset;
}
static int map_sg(struct device *dev, struct scatterlist *sgl,
int nents, enum dma_data_direction direction,
struct dma_attrs *attrs)
{
struct scatterlist *sg;
int i;
for_each_sg(sgl, sg, nents, i) {
sg->dma_address = sg_phys(sg);
}
return nents;
}
struct dma_map_ops h8300_dma_map_ops = {
.alloc = dma_alloc,
.free = dma_free,
.map_page = map_page,
.map_sg = map_sg,
};
EXPORT_SYMBOL(h8300_dma_map_ops);
/*
*
* linux/arch/h8300/kernel/entry.S
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
* David McCullough <davidm@snapgear.com>
*
*/
/*
* entry.S
* include exception/interrupt gateway
* system call entry
*/
#include <linux/sys.h>
#include <asm/unistd.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/errno.h>
#if defined(CONFIG_CPU_H8300H)
#define USERRET 8
INTERRUPTS = 64
.h8300h
.macro SHLL2 reg
shll.l \reg
shll.l \reg
.endm
.macro SHLR2 reg
shlr.l \reg
shlr.l \reg
.endm
.macro SAVEREGS
mov.l er0,@-sp
mov.l er1,@-sp
mov.l er2,@-sp
mov.l er3,@-sp
.endm
.macro RESTOREREGS
mov.l @sp+,er3
mov.l @sp+,er2
.endm
.macro SAVEEXR
.endm
.macro RESTOREEXR
.endm
#endif
#if defined(CONFIG_CPU_H8S)
#define USERRET 10
#define USEREXR 8
INTERRUPTS = 128
.h8300s
.macro SHLL2 reg
shll.l #2,\reg
.endm
.macro SHLR2 reg
shlr.l #2,\reg
.endm
.macro SAVEREGS
stm.l er0-er3,@-sp
.endm
.macro RESTOREREGS
ldm.l @sp+,er2-er3
.endm
.macro SAVEEXR
mov.w @(USEREXR:16,er0),r1
mov.w r1,@(LEXR-LER3:16,sp) /* copy EXR */
.endm
.macro RESTOREEXR
mov.w @(LEXR-LER1:16,sp),r1 /* restore EXR */
mov.b r1l,r1h
mov.w r1,@(USEREXR:16,er0)
.endm
#endif
/* CPU context save/restore macros. */
.macro SAVE_ALL
mov.l er0,@-sp
stc ccr,r0l /* check kernel mode */
btst #4,r0l
bne 5f
/* user mode */
mov.l sp,@_sw_usp
mov.l @sp,er0 /* restore saved er0 */
orc #0x10,ccr /* switch kernel stack */
mov.l @_sw_ksp,sp
sub.l #(LRET-LORIG),sp /* allocate LORIG - LRET */
SAVEREGS
mov.l @_sw_usp,er0
mov.l @(USERRET:16,er0),er1 /* copy the RET addr */
mov.l er1,@(LRET-LER3:16,sp)
SAVEEXR
mov.l @(LORIG-LER3:16,sp),er0
mov.l er0,@(LER0-LER3:16,sp) /* copy ER0 */
mov.w e1,r1 /* e1 highbyte = ccr */
and #0xef,r1h /* mask mode? flag */
bra 6f
5:
/* kernel mode */
mov.l @sp,er0 /* restore saved er0 */
subs #2,sp /* set dummy ccr */
subs #4,sp /* set dummp sp */
SAVEREGS
mov.w @(LRET-LER3:16,sp),r1 /* copy old ccr */
6:
mov.b r1h,r1l
mov.b #0,r1h
mov.w r1,@(LCCR-LER3:16,sp) /* set ccr */
mov.l @_sw_usp,er2
mov.l er2,@(LSP-LER3:16,sp) /* set usp */
mov.l er6,@-sp /* syscall arg #6 */
mov.l er5,@-sp /* syscall arg #5 */
mov.l er4,@-sp /* syscall arg #4 */
.endm /* r1 = ccr */
.macro RESTORE_ALL
mov.l @sp+,er4
mov.l @sp+,er5
mov.l @sp+,er6
RESTOREREGS
mov.w @(LCCR-LER1:16,sp),r0 /* check kernel mode */
btst #4,r0l
bne 7f
orc #0xc0,ccr
mov.l @(LSP-LER1:16,sp),er0
mov.l @(LER0-LER1:16,sp),er1 /* restore ER0 */
mov.l er1,@er0
RESTOREEXR
mov.w @(LCCR-LER1:16,sp),r1 /* restore the RET addr */
mov.b r1l,r1h
mov.b @(LRET+1-LER1:16,sp),r1l
mov.w r1,e1
mov.w @(LRET+2-LER1:16,sp),r1
mov.l er1,@(USERRET:16,er0)
mov.l @sp+,er1
add.l #(LRET-LER1),sp /* remove LORIG - LRET */
mov.l sp,@_sw_ksp
andc #0xef,ccr /* switch to user mode */
mov.l er0,sp
bra 8f
7:
mov.l @sp+,er1
add.l #10,sp
8:
mov.l @sp+,er0
adds #4,sp /* remove the sw created LVEC */
rte
.endm
.globl _system_call
.globl ret_from_exception
.globl ret_from_fork
.globl ret_from_kernel_thread
.globl ret_from_interrupt
.globl _interrupt_redirect_table
.globl _sw_ksp,_sw_usp
.globl _resume
.globl _interrupt_entry
.globl _trace_break
.globl _nmi
#if defined(CONFIG_ROMKERNEL)
.section .int_redirect,"ax"
_interrupt_redirect_table:
#if defined(CONFIG_CPU_H8300H)
.rept 7
.long 0
.endr
#endif
#if defined(CONFIG_CPU_H8S)
.rept 5
.long 0
.endr
jmp @_trace_break
.long 0
#endif
jsr @_interrupt_entry /* NMI */
jmp @_system_call /* TRAPA #0 (System call) */
.long 0
.long 0
jmp @_trace_break /* TRAPA #3 (breakpoint) */
.rept INTERRUPTS-12
jsr @_interrupt_entry
.endr
#endif
#if defined(CONFIG_RAMKERNEL)
.globl _interrupt_redirect_table
.section .bss
_interrupt_redirect_table:
.space 4
#endif
.section .text
.align 2
_interrupt_entry:
SAVE_ALL
/* r1l is saved ccr */
mov.l sp,er0
add.l #LVEC,er0
btst #4,r1l
bne 1f
/* user LVEC */
mov.l @_sw_usp,er0
adds #4,er0
1:
mov.l @er0,er0 /* LVEC address */
#if defined(CONFIG_ROMKERNEL)
sub.l #_interrupt_redirect_table,er0
#endif
#if defined(CONFIG_RAMKERNEL)
mov.l @_interrupt_redirect_table,er1
sub.l er1,er0
#endif
SHLR2 er0
dec.l #1,er0
mov.l sp,er1
subs #4,er1 /* adjust ret_pc */
#if defined(CONFIG_CPU_H8S)
orc #7,exr
#endif
jsr @do_IRQ
jmp @ret_from_interrupt
_system_call:
subs #4,sp /* dummy LVEC */
SAVE_ALL
/* er0: syscall nr */
andc #0xbf,ccr
mov.l er0,er4
/* save top of frame */
mov.l sp,er0
jsr @set_esp0
mov.l sp,er2
and.w #0xe000,r2
mov.l @(TI_FLAGS:16,er2),er2
and.w #_TIF_WORK_SYSCALL_MASK,r2
beq 1f
mov.l sp,er0
jsr @do_syscall_trace_enter
1:
cmp.l #__NR_syscalls,er4
bcc badsys
SHLL2 er4
mov.l #_sys_call_table,er0
add.l er4,er0
mov.l @er0,er4
beq ret_from_exception:16
mov.l @(LER1:16,sp),er0
mov.l @(LER2:16,sp),er1
mov.l @(LER3:16,sp),er2
jsr @er4
mov.l er0,@(LER0:16,sp) /* save the return value */
mov.l sp,er2
and.w #0xe000,r2
mov.l @(TI_FLAGS:16,er2),er2
and.w #_TIF_WORK_SYSCALL_MASK,r2
beq 2f
mov.l sp,er0
jsr @do_syscall_trace_leave
2:
orc #0xc0,ccr
bra resume_userspace
badsys:
mov.l #-ENOSYS,er0
mov.l er0,@(LER0:16,sp)
bra resume_userspace
#if !defined(CONFIG_PREEMPT)
#define resume_kernel restore_all
#endif
ret_from_exception:
#if defined(CONFIG_PREEMPT)
orc #0xc0,ccr
#endif
ret_from_interrupt:
mov.b @(LCCR+1:16,sp),r0l
btst #4,r0l
bne resume_kernel:16 /* return from kernel */
resume_userspace:
andc #0xbf,ccr
mov.l sp,er4
and.w #0xe000,r4 /* er4 <- current thread info */
mov.l @(TI_FLAGS:16,er4),er1
and.l #_TIF_WORK_MASK,er1
beq restore_all:8
work_pending:
btst #TIF_NEED_RESCHED,r1l
bne work_resched:8
/* work notifysig */
mov.l sp,er0
subs #4,er0 /* er0: pt_regs */
jsr @do_notify_resume
bra resume_userspace:8
work_resched:
mov.l sp,er0
jsr @set_esp0
jsr @schedule
bra resume_userspace:8
restore_all:
RESTORE_ALL /* Does RTE */
#if defined(CONFIG_PREEMPT)
resume_kernel:
mov.l @(TI_PRE_COUNT:16,er4),er0
bne restore_all:8
need_resched:
mov.l @(TI_FLAGS:16,er4),er0
btst #TIF_NEED_RESCHED,r0l
beq restore_all:8
mov.b @(LCCR+1:16,sp),r0l /* Interrupt Enabled? */
bmi restore_all:8
mov.l sp,er0
jsr @set_esp0
jsr @preempt_schedule_irq
bra need_resched:8
#endif
ret_from_fork:
mov.l er2,er0
jsr @schedule_tail
jmp @ret_from_exception
ret_from_kernel_thread:
mov.l er2,er0
jsr @schedule_tail
mov.l @(LER4:16,sp),er0
mov.l @(LER5:16,sp),er1
jsr @er1
jmp @ret_from_exception
_resume:
/*
* Beware - when entering resume, offset of tss is in d1,
* prev (the current task) is in a0, next (the new task)
* is in a1 and d2.b is non-zero if the mm structure is
* shared between the tasks, so don't change these
* registers until their contents are no longer needed.
*/
/* save sr */
sub.w r3,r3
stc ccr,r3l
mov.w r3,@(THREAD_CCR+2:16,er0)
/* disable interrupts */
orc #0xc0,ccr
mov.l @_sw_usp,er3
mov.l er3,@(THREAD_USP:16,er0)
mov.l sp,@(THREAD_KSP:16,er0)
/* Skip address space switching if they are the same. */
/* FIXME: what did we hack out of here, this does nothing! */
mov.l @(THREAD_USP:16,er1),er0
mov.l er0,@_sw_usp
mov.l @(THREAD_KSP:16,er1),sp
/* restore status register */
mov.w @(THREAD_CCR+2:16,er1),r3
ldc r3l,ccr
rts
_trace_break:
subs #4,sp
SAVE_ALL
sub.l er1,er1
dec.l #1,er1
mov.l er1,@(LORIG,sp)
mov.l sp,er0
jsr @set_esp0
mov.l @_sw_usp,er0
mov.l @er0,er1
mov.w @(-2:16,er1),r2
cmp.w #0x5730,r2
beq 1f
subs #2,er1
mov.l er1,@er0
1:
and.w #0xff,e1
mov.l er1,er0
jsr @trace_trap
jmp @ret_from_exception
_nmi:
subs #4, sp
mov.l er0, @-sp
mov.l @_interrupt_redirect_table, er0
add.l #8*4, er0
mov.l er0, @(4,sp)
mov.l @sp+, er0
jmp @_interrupt_entry
.section .bss
_sw_ksp:
.space 4
_sw_usp:
.space 4
.end
#include <linux/module.h>
#include <linux/linkage.h>
/*
* libgcc functions - functions that are used internally by the
* compiler... (prototypes are not correct though, but that
* doesn't really matter since they're not versioned).
*/
asmlinkage long __ucmpdi2(long long, long long);
asmlinkage long long __ashldi3(long long, int);
asmlinkage long long __ashrdi3(long long, int);
asmlinkage long long __lshrdi3(long long, int);
asmlinkage long __divsi3(long, long);
asmlinkage long __modsi3(long, long);
asmlinkage unsigned long __umodsi3(unsigned long, unsigned long);
asmlinkage long long __muldi3(long long, long long);
asmlinkage long __mulsi3(long, long);
asmlinkage long __udivsi3(long, long);
asmlinkage void *memcpy(void *, const void *, size_t);
asmlinkage void *memset(void *, int, size_t);
asmlinkage long strncpy_from_user(void *to, void *from, size_t n);
/* gcc lib functions */
EXPORT_SYMBOL(__ucmpdi2);
EXPORT_SYMBOL(__ashldi3);
EXPORT_SYMBOL(__ashrdi3);
EXPORT_SYMBOL(__lshrdi3);
EXPORT_SYMBOL(__divsi3);
EXPORT_SYMBOL(__modsi3);
EXPORT_SYMBOL(__umodsi3);
EXPORT_SYMBOL(__muldi3);
EXPORT_SYMBOL(__mulsi3);
EXPORT_SYMBOL(__udivsi3);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(strncpy_from_user);
#include <linux/sys.h>
#include <linux/init.h>
#include <asm/unistd.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/errno.h>
#if defined(CONFIG_CPU_H8300H)
.h8300h
#define SYSCR 0xfee012
#define IRAMTOP 0xffff20
#endif
#if defined(CONFIG_CPU_H8S)
.h8300s
#define INTCR 0xffff31
#define IRAMTOP 0xffc000
#endif
__HEAD
.global _start
_start:
mov.l #IRAMTOP,sp
/* .bss clear */
mov.l #_sbss,er5
mov.l #_ebss,er4
sub.l er5,er4
shlr er4
shlr er4
sub.l er2,er2
1:
mov.l er2,@er5
adds #4,er5
dec.l #1,er4
bne 1b
jsr @h8300_fdt_init
/* linux kernel start */
#if defined(CONFIG_CPU_H8300H)
ldc #0xd0,ccr /* running kernel */
mov.l #SYSCR,er0
bclr #3,@er0
#endif
#if defined(CONFIG_CPU_H8S)
ldc #0x07,exr
bclr #4,@INTCR:8
bset #5,@INTCR:8 /* Interrupt mode 2 */
ldc #0x90,ccr /* running kernel */
#endif
mov.l #init_thread_union,sp
add.l #0x2000,sp
jsr @start_kernel
1:
bra 1b
.end
#include <linux/init.h>
#include <asm/thread_info.h>
#if defined(CONFIG_CPU_H8300H)
.h8300h
#define SYSCR 0xfee012
#define IRAMTOP 0xffff20
#define NR_INT 64
#endif
#if defined(CONFIG_CPU_H8S)
.h8300s
#define INTCR 0xffff31
#define IRAMTOP 0xffc000
#define NR_INT 128
#endif
__HEAD
.global _start
_start:
mov.l #IRAMTOP,sp
#if !defined(CONFIG_H8300H_SIM) && \
!defined(CONFIG_H8S_SIM)
jsr @lowlevel_init
/* copy .data */
mov.l #_begin_data,er5
mov.l #_sdata,er6
mov.l #_edata,er4
sub.l er6,er4
shlr.l er4
shlr.l er4
1:
mov.l @er5+,er0
mov.l er0,@er6
adds #4,er6
dec.l #1,er4
bne 1b
/* .bss clear */
mov.l #_sbss,er5
mov.l #_ebss,er4
sub.l er5,er4
shlr er4
shlr er4
sub.l er0,er0
1:
mov.l er0,@er5
adds #4,er5
dec.l #1,er4
bne 1b
#else
/* get cmdline from gdb */
jsr @0xcc
;; er0 - argc
;; er1 - argv
mov.l #command_line,er3
adds #4,er1
dec.l #1,er0
beq 4f
1:
mov.l @er1+,er2
2:
mov.b @er2+,r4l
beq 3f
mov.b r4l,@er3
adds #1,er3
bra 2b
3:
mov.b #' ',r4l
mov.b r4l,@er3
adds #1,er3
dec.l #1,er0
bne 1b
subs #1,er3
mov.b #0,r4l
mov.b r4l,@er3
4:
#endif
sub.l er0,er0
jsr @h8300_fdt_init
/* linux kernel start */
#if defined(CONFIG_CPU_H8300H)
ldc #0xd0,ccr /* running kernel */
mov.l #SYSCR,er0
bclr #3,@er0
#endif
#if defined(CONFIG_CPU_H8S)
ldc #0x07,exr
bclr #4,@INTCR:8
bset #5,@INTCR:8 /* Interrupt mode 2 */
ldc #0x90,ccr /* running kernel */
#endif
mov.l #init_thread_union,sp
add.l #0x2000,sp
jsr @start_kernel
1:
bra 1b
#if defined(CONFIG_ROMKERNEL)
/* interrupt vector */
.section .vectors,"ax"
.long _start
.long _start
vector = 2
.rept NR_INT - 2
.long _interrupt_redirect_table+vector*4
vector = vector + 1
.endr
#endif
.end
/*
* linux/arch/h8300/kernel/irq.c
*
* Copyright 2014-2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/of_irq.h>
#include <asm/traps.h>
#ifdef CONFIG_RAMKERNEL
typedef void (*h8300_vector)(void);
static const h8300_vector __initconst trap_table[] = {
0, 0, 0, 0,
_trace_break,
0, 0,
_nmi,
_system_call,
0, 0,
_trace_break,
};
static unsigned long __init *get_vector_address(void)
{
unsigned long *rom_vector = CPU_VECTOR;
unsigned long base, tmp;
int vec_no;
base = rom_vector[EXT_IRQ0] & ADDR_MASK;
/* check romvector format */
for (vec_no = EXT_IRQ0 + 1; vec_no <= EXT_IRQ0+EXT_IRQS; vec_no++) {
if ((base+(vec_no - EXT_IRQ0)*4) !=
(rom_vector[vec_no] & ADDR_MASK))
return NULL;
}
/* ramvector base address */
base -= EXT_IRQ0*4;
/* writerble? */
tmp = ~(*(volatile unsigned long *)base);
(*(volatile unsigned long *)base) = tmp;
if ((*(volatile unsigned long *)base) != tmp)
return NULL;
return (unsigned long *)base;
}
static void __init setup_vector(void)
{
int i;
unsigned long *ramvec, *ramvec_p;
const h8300_vector *trap_entry;
ramvec = get_vector_address();
if (ramvec == NULL)
panic("interrupt vector serup failed.");
else
pr_debug("virtual vector at 0x%p\n", ramvec);
/* create redirect table */
ramvec_p = ramvec;
trap_entry = trap_table;
for (i = 0; i < NR_IRQS; i++) {
if (i < 12) {
if (*trap_entry)
*ramvec_p = VECTOR(*trap_entry);
ramvec_p++;
trap_entry++;
} else
*ramvec_p++ = REDIRECT(_interrupt_entry);
}
_interrupt_redirect_table = ramvec;
}
#else
void setup_vector(void)
{
/* noting do */
}
#endif
void __init init_IRQ(void)
{
setup_vector();
irqchip_init();
}
asmlinkage void do_IRQ(int irq)
{
irq_enter();
generic_handle_irq(irq);
irq_exit();
}
#include <linux/moduleloader.h>
#include <linux/elf.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
struct module *me)
{
unsigned int i;
Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
pr_debug("Applying relocate section %u to %u\n", relsec,
sechdrs[relsec].sh_info);
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
/* This is where to make the change */
uint32_t *loc =
(uint32_t *)(sechdrs[sechdrs[relsec].sh_info].sh_addr
+ rela[i].r_offset);
/* This is the symbol it is referring to. Note that all
undefined symbols have been resolved. */
Elf32_Sym *sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ ELF32_R_SYM(rela[i].r_info);
uint32_t v = sym->st_value + rela[i].r_addend;
switch (ELF32_R_TYPE(rela[i].r_info)) {
case R_H8_DIR24R8:
loc = (uint32_t *)((uint32_t)loc - 1);
*loc = (*loc & 0xff000000) | ((*loc & 0xffffff) + v);
break;
case R_H8_DIR24A8:
if (ELF32_R_SYM(rela[i].r_info))
*loc += v;
break;
case R_H8_DIR32:
case R_H8_DIR32A16:
*loc += v;
break;
case R_H8_PCREL16:
v -= (unsigned long)loc + 2;
if ((Elf32_Sword)v > 0x7fff ||
(Elf32_Sword)v < -(Elf32_Sword)0x8000)
goto overflow;
else
*(unsigned short *)loc = v;
break;
case R_H8_PCREL8:
v -= (unsigned long)loc + 1;
if ((Elf32_Sword)v > 0x7f ||
(Elf32_Sword)v < -(Elf32_Sword)0x80)
goto overflow;
else
*(unsigned char *)loc = v;
break;
default:
pr_err("module %s: Unknown relocation: %u\n",
me->name, ELF32_R_TYPE(rela[i].r_info));
return -ENOEXEC;
}
}
return 0;
overflow:
pr_err("module %s: relocation offset overflow: %08x\n",
me->name, rela[i].r_offset);
return -ENOEXEC;
}
/*
* linux/arch/h8300/kernel/process.c
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
*
* Based on:
*
* linux/arch/m68knommu/kernel/process.c
*
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
* Kenneth Albanowski <kjahds@kjahds.com>,
* The Silver Hammer Group, Ltd.
*
* linux/arch/m68k/kernel/process.c
*
* Copyright (C) 1995 Hamish Macdonald
*
* 68060 fixes by Jesper Skov
*/
/*
* This file handles the architecture-dependent parts of process handling..
*/
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <asm/uaccess.h>
#include <asm/traps.h>
#include <asm/setup.h>
#include <asm/pgtable.h>
void (*pm_power_off)(void) = NULL;
EXPORT_SYMBOL(pm_power_off);
asmlinkage void ret_from_fork(void);
asmlinkage void ret_from_kernel_thread(void);
/*
* The idle loop on an H8/300..
*/
void arch_cpu_idle(void)
{
local_irq_enable();
__asm__("sleep");
}
void machine_restart(char *__unused)
{
local_irq_disable();
__asm__("jmp @@0");
}
void machine_halt(void)
{
local_irq_disable();
__asm__("sleep");
for (;;)
;
}
void machine_power_off(void)
{
local_irq_disable();
__asm__("sleep");
for (;;)
;
}
void show_regs(struct pt_regs *regs)
{
show_regs_print_info(KERN_DEFAULT);
pr_notice("\n");
pr_notice("PC: %08lx Status: %02x\n",
regs->pc, regs->ccr);
pr_notice("ORIG_ER0: %08lx ER0: %08lx ER1: %08lx\n",
regs->orig_er0, regs->er0, regs->er1);
pr_notice("ER2: %08lx ER3: %08lx ER4: %08lx ER5: %08lx\n",
regs->er2, regs->er3, regs->er4, regs->er5);
pr_notice("ER6' %08lx ", regs->er6);
if (user_mode(regs))
printk("USP: %08lx\n", rdusp());
else
printk("\n");
}
void flush_thread(void)
{
}
int copy_thread(unsigned long clone_flags,
unsigned long usp, unsigned long topstk,
struct task_struct *p)
{
struct pt_regs *childregs;
childregs = (struct pt_regs *) (THREAD_SIZE + task_stack_page(p)) - 1;
if (unlikely(p->flags & PF_KTHREAD)) {
memset(childregs, 0, sizeof(struct pt_regs));
childregs->retpc = (unsigned long) ret_from_kernel_thread;
childregs->er4 = topstk; /* arg */
childregs->er5 = usp; /* fn */
} else {
*childregs = *current_pt_regs();
childregs->er0 = 0;
childregs->retpc = (unsigned long) ret_from_fork;
p->thread.usp = usp ?: rdusp();
}
p->thread.ksp = (unsigned long)childregs;
return 0;
}
unsigned long thread_saved_pc(struct task_struct *tsk)
{
return ((struct pt_regs *)tsk->thread.esp0)->pc;
}
unsigned long get_wchan(struct task_struct *p)
{
unsigned long fp, pc;
unsigned long stack_page;
int count = 0;
if (!p || p == current || p->state == TASK_RUNNING)
return 0;
stack_page = (unsigned long)p;
fp = ((struct pt_regs *)p->thread.ksp)->er6;
do {
if (fp < stack_page+sizeof(struct thread_info) ||
fp >= 8184+stack_page)
return 0;
pc = ((unsigned long *)fp)[1];
if (!in_sched_functions(pc))
return pc;
fp = *(unsigned long *) fp;
} while (count++ < 16);
return 0;
}
/* generic sys_clone is not enough registers */
asmlinkage int sys_clone(unsigned long __user *args)
{
unsigned long clone_flags;
unsigned long newsp;
uintptr_t parent_tidptr;
uintptr_t child_tidptr;
get_user(clone_flags, &args[0]);
get_user(newsp, &args[1]);
get_user(parent_tidptr, &args[2]);
get_user(child_tidptr, &args[3]);
return do_fork(clone_flags, newsp, 0,
(int __user *)parent_tidptr, (int __user *)child_tidptr);
}
/*
* linux/arch/h8300/kernel/ptrace.c
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*
* 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/errno.h>
#include <linux/ptrace.h>
#include <linux/audit.h>
#include <linux/tracehook.h>
#include <linux/regset.h>
#include <linux/elf.h>
#define CCR_MASK 0x6f /* mode/imask not set */
#define EXR_MASK 0x80 /* modify only T */
#define PT_REG(r) offsetof(struct pt_regs, r)
extern void user_disable_single_step(struct task_struct *child);
/* Mapping from PT_xxx to the stack offset at which the register is
saved. Notice that usp has no stack-slot and needs to be treated
specially (see get_reg/put_reg below). */
static const int register_offset[] = {
PT_REG(er1), PT_REG(er2), PT_REG(er3), PT_REG(er4),
PT_REG(er5), PT_REG(er6), PT_REG(er0), -1,
PT_REG(orig_er0), PT_REG(ccr), PT_REG(pc),
#if defined(CONFIG_CPU_H8S)
PT_REG(exr),
#endif
};
/* read register */
long h8300_get_reg(struct task_struct *task, int regno)
{
switch (regno) {
case PT_USP:
return task->thread.usp + sizeof(long)*2;
case PT_CCR:
case PT_EXR:
return *(unsigned short *)(task->thread.esp0 +
register_offset[regno]);
default:
return *(unsigned long *)(task->thread.esp0 +
register_offset[regno]);
}
}
int h8300_put_reg(struct task_struct *task, int regno, unsigned long data)
{
unsigned short oldccr;
unsigned short oldexr;
switch (regno) {
case PT_USP:
task->thread.usp = data - sizeof(long)*2;
case PT_CCR:
oldccr = *(unsigned short *)(task->thread.esp0 +
register_offset[regno]);
oldccr &= ~CCR_MASK;
data &= CCR_MASK;
data |= oldccr;
*(unsigned short *)(task->thread.esp0 +
register_offset[regno]) = data;
break;
case PT_EXR:
oldexr = *(unsigned short *)(task->thread.esp0 +
register_offset[regno]);
oldccr &= ~EXR_MASK;
data &= EXR_MASK;
data |= oldexr;
*(unsigned short *)(task->thread.esp0 +
register_offset[regno]) = data;
break;
default:
*(unsigned long *)(task->thread.esp0 +
register_offset[regno]) = data;
break;
}
return 0;
}
static int regs_get(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
void *kbuf, void __user *ubuf)
{
int r;
struct user_regs_struct regs;
long *reg = (long *)&regs;
/* build user regs in buffer */
for (r = 0; r < ARRAY_SIZE(register_offset); r++)
*reg++ = h8300_get_reg(target, r);
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
&regs, 0, sizeof(regs));
}
static int regs_set(struct task_struct *target,
const struct user_regset *regset,
unsigned int pos, unsigned int count,
const void *kbuf, const void __user *ubuf)
{
int r;
int ret;
struct user_regs_struct regs;
long *reg;
/* build user regs in buffer */
for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
*reg++ = h8300_get_reg(target, r);
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
&regs, 0, sizeof(regs));
if (ret)
return ret;
/* write back to pt_regs */
for (reg = (long *)&regs, r = 0; r < ARRAY_SIZE(register_offset); r++)
h8300_put_reg(target, r, *reg++);
return 0;
}
enum h8300_regset {
REGSET_GENERAL,
};
static const struct user_regset h8300_regsets[] = {
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
.n = ELF_NGREG,
.size = sizeof(long),
.align = sizeof(long),
.get = regs_get,
.set = regs_set,
},
};
static const struct user_regset_view user_h8300_native_view = {
.name = "h8300",
.e_machine = EM_H8_300,
.regsets = h8300_regsets,
.n = ARRAY_SIZE(h8300_regsets),
};
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
{
return &user_h8300_native_view;
}
void ptrace_disable(struct task_struct *child)
{
user_disable_single_step(child);
}
long arch_ptrace(struct task_struct *child, long request,
unsigned long addr, unsigned long data)
{
int ret;
switch (request) {
default:
ret = ptrace_request(child, request, addr, data);
break;
}
return ret;
}
asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
{
long ret = 0;
if (test_thread_flag(TIF_SYSCALL_TRACE) &&
tracehook_report_syscall_entry(regs))
/*
* Tracing decided this syscall should not happen.
* We'll return a bogus call number to get an ENOSYS
* error, but leave the original number in regs->regs[0].
*/
ret = -1L;
audit_syscall_entry(regs->er1, regs->er2, regs->er3,
regs->er4, regs->er5);
return ret ?: regs->er0;
}
asmlinkage void do_syscall_trace_leave(struct pt_regs *regs)
{
int step;
audit_syscall_exit(regs);
step = test_thread_flag(TIF_SINGLESTEP);
if (step || test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall_exit(regs, step);
}
/*
* ptrace cpu depend helper functions
*
* Copyright 2003, 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*
* 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/linkage.h>
#include <linux/sched.h>
#include <asm/ptrace.h>
#define BREAKINST 0x5730 /* trapa #3 */
/* disable singlestep */
void user_disable_single_step(struct task_struct *child)
{
if ((long)child->thread.breakinfo.addr != -1L) {
*(child->thread.breakinfo.addr) = child->thread.breakinfo.inst;
child->thread.breakinfo.addr = (unsigned short *)-1L;
}
}
/* calculate next pc */
enum jump_type {none, /* normal instruction */
jabs, /* absolute address jump */
ind, /* indirect address jump */
ret, /* return to subrutine */
reg, /* register indexed jump */
relb, /* pc relative jump (byte offset) */
relw, /* pc relative jump (word offset) */
};
/* opcode decode table define
ptn: opcode pattern
msk: opcode bitmask
len: instruction length (<0 next table index)
jmp: jump operation mode */
struct optable {
unsigned char bitpattern;
unsigned char bitmask;
signed char length;
signed char type;
} __packed __aligned(1);
#define OPTABLE(ptn, msk, len, jmp) \
{ \
.bitpattern = ptn, \
.bitmask = msk, \
.length = len, \
.type = jmp, \
}
static const struct optable optable_0[] = {
OPTABLE(0x00, 0xff, 1, none), /* 0x00 */
OPTABLE(0x01, 0xff, -1, none), /* 0x01 */
OPTABLE(0x02, 0xfe, 1, none), /* 0x02-0x03 */
OPTABLE(0x04, 0xee, 1, none), /* 0x04-0x05/0x14-0x15 */
OPTABLE(0x06, 0xfe, 1, none), /* 0x06-0x07 */
OPTABLE(0x08, 0xea, 1, none), /* 0x08-0x09/0x0c-0x0d/0x18-0x19/0x1c-0x1d */
OPTABLE(0x0a, 0xee, 1, none), /* 0x0a-0x0b/0x1a-0x1b */
OPTABLE(0x0e, 0xee, 1, none), /* 0x0e-0x0f/0x1e-0x1f */
OPTABLE(0x10, 0xfc, 1, none), /* 0x10-0x13 */
OPTABLE(0x16, 0xfe, 1, none), /* 0x16-0x17 */
OPTABLE(0x20, 0xe0, 1, none), /* 0x20-0x3f */
OPTABLE(0x40, 0xf0, 1, relb), /* 0x40-0x4f */
OPTABLE(0x50, 0xfc, 1, none), /* 0x50-0x53 */
OPTABLE(0x54, 0xfd, 1, ret), /* 0x54/0x56 */
OPTABLE(0x55, 0xff, 1, relb), /* 0x55 */
OPTABLE(0x57, 0xff, 1, none), /* 0x57 */
OPTABLE(0x58, 0xfb, 2, relw), /* 0x58/0x5c */
OPTABLE(0x59, 0xfb, 1, reg), /* 0x59/0x5b */
OPTABLE(0x5a, 0xfb, 2, jabs), /* 0x5a/0x5e */
OPTABLE(0x5b, 0xfb, 2, ind), /* 0x5b/0x5f */
OPTABLE(0x60, 0xe8, 1, none), /* 0x60-0x67/0x70-0x77 */
OPTABLE(0x68, 0xfa, 1, none), /* 0x68-0x69/0x6c-0x6d */
OPTABLE(0x6a, 0xfe, -2, none), /* 0x6a-0x6b */
OPTABLE(0x6e, 0xfe, 2, none), /* 0x6e-0x6f */
OPTABLE(0x78, 0xff, 4, none), /* 0x78 */
OPTABLE(0x79, 0xff, 2, none), /* 0x79 */
OPTABLE(0x7a, 0xff, 3, none), /* 0x7a */
OPTABLE(0x7b, 0xff, 2, none), /* 0x7b */
OPTABLE(0x7c, 0xfc, 2, none), /* 0x7c-0x7f */
OPTABLE(0x80, 0x80, 1, none), /* 0x80-0xff */
};
static const struct optable optable_1[] = {
OPTABLE(0x00, 0xff, -3, none), /* 0x0100 */
OPTABLE(0x40, 0xf0, -3, none), /* 0x0140-0x14f */
OPTABLE(0x80, 0xf0, 1, none), /* 0x0180-0x018f */
OPTABLE(0xc0, 0xc0, 2, none), /* 0x01c0-0x01ff */
};
static const struct optable optable_2[] = {
OPTABLE(0x00, 0x20, 2, none), /* 0x6a0?/0x6a8?/0x6b0?/0x6b8? */
OPTABLE(0x20, 0x20, 3, none), /* 0x6a2?/0x6aa?/0x6b2?/0x6ba? */
};
static const struct optable optable_3[] = {
OPTABLE(0x69, 0xfb, 2, none), /* 0x010069/0x01006d/014069/0x01406d */
OPTABLE(0x6b, 0xff, -4, none), /* 0x01006b/0x01406b */
OPTABLE(0x6f, 0xff, 3, none), /* 0x01006f/0x01406f */
OPTABLE(0x78, 0xff, 5, none), /* 0x010078/0x014078 */
};
static const struct optable optable_4[] = {
/* 0x0100690?/0x01006d0?/0140690?/0x01406d0?/
0x0100698?/0x01006d8?/0140698?/0x01406d8? */
OPTABLE(0x00, 0x78, 3, none),
/* 0x0100692?/0x01006d2?/0140692?/0x01406d2?/
0x010069a?/0x01006da?/014069a?/0x01406da? */
OPTABLE(0x20, 0x78, 4, none),
};
static const struct optables_list {
const struct optable *ptr;
int size;
} optables[] = {
#define OPTABLES(no) \
{ \
.ptr = optable_##no, \
.size = sizeof(optable_##no) / sizeof(struct optable), \
}
OPTABLES(0),
OPTABLES(1),
OPTABLES(2),
OPTABLES(3),
OPTABLES(4),
};
const unsigned char condmask[] = {
0x00, 0x40, 0x01, 0x04, 0x02, 0x08, 0x10, 0x20
};
static int isbranch(struct task_struct *task, int reson)
{
unsigned char cond = h8300_get_reg(task, PT_CCR);
/* encode complex conditions */
/* B4: N^V
B5: Z|(N^V)
B6: C|Z */
__asm__("bld #3,%w0\n\t"
"bxor #1,%w0\n\t"
"bst #4,%w0\n\t"
"bor #2,%w0\n\t"
"bst #5,%w0\n\t"
"bld #2,%w0\n\t"
"bor #0,%w0\n\t"
"bst #6,%w0\n\t"
: "=&r"(cond) : "0"(cond) : "cc");
cond &= condmask[reson >> 1];
if (!(reson & 1))
return cond == 0;
else
return cond != 0;
}
static unsigned short *decode(struct task_struct *child,
const struct optable *op,
char *fetch_p, unsigned short *pc,
unsigned char inst)
{
unsigned long addr;
unsigned long *sp;
int regno;
switch (op->type) {
case none:
return (unsigned short *)pc + op->length;
case jabs:
addr = *(unsigned long *)pc;
return (unsigned short *)(addr & 0x00ffffff);
case ind:
addr = *pc & 0xff;
return (unsigned short *)(*(unsigned long *)addr);
case ret:
sp = (unsigned long *)h8300_get_reg(child, PT_USP);
/* user stack frames
| er0 | temporary saved
+--------+
| exp | exception stack frames
+--------+
| ret pc | userspace return address
*/
return (unsigned short *)(*(sp+2) & 0x00ffffff);
case reg:
regno = (*pc >> 4) & 0x07;
if (regno == 0)
addr = h8300_get_reg(child, PT_ER0);
else
addr = h8300_get_reg(child, regno-1 + PT_ER1);
return (unsigned short *)addr;
case relb:
if (inst == 0x55 || isbranch(child, inst & 0x0f))
pc = (unsigned short *)((unsigned long)pc +
((signed char)(*fetch_p)));
return pc+1; /* skip myself */
case relw:
if (inst == 0x5c || isbranch(child, (*fetch_p & 0xf0) >> 4))
pc = (unsigned short *)((unsigned long)pc +
((signed short)(*(pc+1))));
return pc+2; /* skip myself */
default:
return NULL;
}
}
static unsigned short *nextpc(struct task_struct *child, unsigned short *pc)
{
const struct optable *op;
unsigned char *fetch_p;
int op_len;
unsigned char inst;
op = optables[0].ptr;
op_len = optables[0].size;
fetch_p = (unsigned char *)pc;
inst = *fetch_p++;
do {
if ((inst & op->bitmask) == op->bitpattern) {
if (op->length < 0) {
op = optables[-op->length].ptr;
op_len = optables[-op->length].size + 1;
inst = *fetch_p++;
} else
return decode(child, op, fetch_p, pc, inst);
} else
op++;
} while (--op_len > 0);
return NULL;
}
/* Set breakpoint(s) to simulate a single step from the current PC. */
void user_enable_single_step(struct task_struct *child)
{
unsigned short *next;
next = nextpc(child, (unsigned short *)h8300_get_reg(child, PT_PC));
child->thread.breakinfo.addr = next;
child->thread.breakinfo.inst = *next;
*next = BREAKINST;
}
asmlinkage void trace_trap(unsigned long bp)
{
if ((unsigned long)current->thread.breakinfo.addr == bp) {
user_disable_single_step(current);
force_sig(SIGTRAP, current);
} else
force_sig(SIGILL, current);
}
/*
* linux/arch/h8300/kernel/ptrace_h8s.c
* ptrace cpu depend helper functions
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
*
* 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/linkage.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/ptrace.h>
#define CCR_MASK 0x6f
#define EXR_TRACE 0x80
/* disable singlestep */
void user_disable_single_step(struct task_struct *child)
{
unsigned char exr;
exr = h8300_get_reg(child, PT_EXR);
exr &= ~EXR_TRACE;
h8300_put_reg(child, PT_EXR, exr);
}
/* enable singlestep */
void user_enable_single_step(struct task_struct *child)
{
unsigned char exr;
exr = h8300_get_reg(child, PT_EXR);
exr |= EXR_TRACE;
h8300_put_reg(child, PT_EXR, exr);
}
asmlinkage void trace_trap(unsigned long bp)
{
(void)bp;
force_sig(SIGTRAP, current);
}
/*
* linux/arch/h8300/kernel/setup.c
*
* Copyright (C) 2001-2014 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
/*
* This file handles the architecture-dependent parts of system setup
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/bootmem.h>
#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/clk-provider.h>
#include <linux/memblock.h>
#include <linux/screen_info.h>
#include <asm/setup.h>
#include <asm/irq.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
#include <asm/page.h>
#if defined(CONFIG_CPU_H8300H)
#define CPU "H8/300H"
#elif defined(CONFIG_CPU_H8S)
#define CPU "H8S"
#else
#define CPU "Unknown"
#endif
unsigned long memory_start;
unsigned long memory_end;
EXPORT_SYMBOL(memory_end);
static unsigned long freq;
extern char __dtb_start[];
#ifdef CONFIG_VT
struct screen_info screen_info;
#endif
char __initdata command_line[COMMAND_LINE_SIZE];
void sim_console_register(void);
void __init h8300_fdt_init(void *fdt, char *bootargs)
{
if (!fdt)
fdt = __dtb_start;
else
strcpy(command_line, bootargs);
early_init_dt_scan(fdt);
memblock_allow_resize();
}
static void __init bootmem_init(void)
{
int bootmap_size;
unsigned long ram_start_pfn;
unsigned long free_ram_start_pfn;
unsigned long ram_end_pfn;
struct memblock_region *region;
memory_end = memory_start = 0;
/* Find main memory where is the kernel */
for_each_memblock(memory, region) {
memory_start = region->base;
memory_end = region->base + region->size;
}
if (!memory_end)
panic("No memory!");
ram_start_pfn = PFN_UP(memory_start);
/* free_ram_start_pfn is first page after kernel */
free_ram_start_pfn = PFN_UP(__pa(_end));
ram_end_pfn = PFN_DOWN(memblock_end_of_DRAM());
max_pfn = ram_end_pfn;
/*
* give all the memory to the bootmap allocator, tell it to put the
* boot mem_map at the start of memory
*/
bootmap_size = init_bootmem_node(NODE_DATA(0),
free_ram_start_pfn,
0,
ram_end_pfn);
/*
* free the usable memory, we have to make sure we do not free
* the bootmem bitmap so we then reserve it after freeing it :-)
*/
free_bootmem(PFN_PHYS(free_ram_start_pfn),
(ram_end_pfn - free_ram_start_pfn) << PAGE_SHIFT);
reserve_bootmem(PFN_PHYS(free_ram_start_pfn), bootmap_size,
BOOTMEM_DEFAULT);
for_each_memblock(reserved, region) {
reserve_bootmem(region->base, region->size, BOOTMEM_DEFAULT);
}
}
void __init setup_arch(char **cmdline_p)
{
unflatten_and_copy_device_tree();
init_mm.start_code = (unsigned long) _stext;
init_mm.end_code = (unsigned long) _etext;
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = (unsigned long) 0;
pr_notice("\r\n\nuClinux " CPU "\n");
pr_notice("Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne\n");
if (*command_line)
strcpy(boot_command_line, command_line);
*cmdline_p = boot_command_line;
parse_early_param();
bootmem_init();
#if defined(CONFIG_H8300H_SIM) || defined(CONFIG_H8S_SIM)
sim_console_register();
#endif
early_platform_driver_probe("earlyprintk", 1, 0);
/*
* get kmalloc into gear
*/
paging_init();
}
/*
* Get CPU information for use by the procfs.
*/
static int show_cpuinfo(struct seq_file *m, void *v)
{
char *cpu;
cpu = CPU;
seq_printf(m, "CPU:\t\t%s\n"
"Clock:\t\t%lu.%1luMHz\n"
"BogoMips:\t%lu.%02lu\n"
"Calibration:\t%lu loops\n",
cpu,
freq/1000, freq%1000,
(loops_per_jiffy*HZ)/500000,
((loops_per_jiffy*HZ)/5000)%100,
(loops_per_jiffy*HZ));
return 0;
}
static void *c_start(struct seq_file *m, loff_t *pos)
{
return *pos < num_possible_cpus() ?
((void *) 0x12345678) : NULL;
}
static void *c_next(struct seq_file *m, void *v, loff_t *pos)
{
++*pos;
return c_start(m, pos);
}
static void c_stop(struct seq_file *m, void *v)
{
}
const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
.show = show_cpuinfo,
};
static int __init device_probe(void)
{
of_platform_populate(NULL, NULL, NULL, NULL);
return 0;
}
device_initcall(device_probe);
#if defined(CONFIG_CPU_H8300H)
#define get_wait(base, addr) ({ \
int baddr; \
baddr = ((addr) / 0x200000 * 2); \
w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1; \
})
#endif
#if defined(CONFIG_CPU_H8S)
#define get_wait(base, addr) ({ \
int baddr; \
baddr = ((addr) / 0x200000 * 16); \
w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1; \
})
#endif
static __init int access_timing(void)
{
struct device_node *bsc;
void __iomem *base;
unsigned long addr = (unsigned long)&__delay;
int bit = 1 << (addr / 0x200000);
int w;
bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc");
base = of_iomap(bsc, 0);
w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1;
if (ctrl_inb((unsigned long)base + 1) & bit)
w *= get_wait(base, addr);
else
w *= 2;
return w * 3 / 2;
}
void __init calibrate_delay(void)
{
struct device_node *cpu;
int freq;
cpu = of_find_compatible_node(NULL, NULL, "renesas,h8300");
of_property_read_s32(cpu, "clock-frequency", &freq);
loops_per_jiffy = freq / HZ / (access_timing() * 2);
pr_cont("%lu.%02lu BogoMIPS (lpj=%lu)\n",
loops_per_jiffy / (500000 / HZ),
(loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy);
}
void __init time_init(void)
{
of_clk_init(NULL);
}
/*
* linux/arch/h8300/kernel/signal.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*
* 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.
*/
/*
* uClinux H8/300 support by Yoshinori Sato <ysato@users.sourceforge.jp>
* and David McCullough <davidm@snapgear.com>
*
* Based on
* Linux/m68k by Hamish Macdonald
*/
/*
* ++roman (07/09/96): implemented signal stacks (specially for tosemu on
* Atari :-) Current limitation: Only one sigstack can be active at one time.
* If a second signal with SA_ONSTACK set arrives while working on a sigstack,
* SA_ONSTACK is ignored. This behaviour avoids lots of trouble with nested
* signal handlers!
*/
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/syscalls.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/highuid.h>
#include <linux/personality.h>
#include <linux/tty.h>
#include <linux/binfmts.h>
#include <linux/tracehook.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
#include <asm/ucontext.h>
/*
* Do a signal return; undo the signal stack.
*
* Keep the return code on the stack quadword aligned!
* That makes the cache flush below easier.
*/
struct rt_sigframe {
long dummy_er0;
long dummy_vector;
#if defined(CONFIG_CPU_H8S)
short dummy_exr;
#endif
long dummy_pc;
char *pretcode;
struct siginfo *pinfo;
void *puc;
unsigned char retcode[8];
struct siginfo info;
struct ucontext uc;
int sig;
} __packed __aligned(2);
static inline int
restore_sigcontext(struct sigcontext *usc, int *pd0)
{
struct pt_regs *regs = current_pt_regs();
int err = 0;
unsigned int ccr;
unsigned int usp;
unsigned int er0;
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
/* restore passed registers */
#define COPY(r) do { err |= get_user(regs->r, &usc->sc_##r); } while (0)
COPY(er1);
COPY(er2);
COPY(er3);
COPY(er5);
COPY(pc);
ccr = regs->ccr & 0x10;
COPY(ccr);
#undef COPY
regs->ccr &= 0xef;
regs->ccr |= ccr;
regs->orig_er0 = -1; /* disable syscall checks */
err |= __get_user(usp, &usc->sc_usp);
wrusp(usp);
err |= __get_user(er0, &usc->sc_er0);
*pd0 = er0;
return err;
}
asmlinkage int sys_rt_sigreturn(void)
{
unsigned long usp = rdusp();
struct rt_sigframe *frame = (struct rt_sigframe *)(usp - 4);
sigset_t set;
int er0;
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
goto badframe;
set_current_blocked(&set);
if (restore_sigcontext(&frame->uc.uc_mcontext, &er0))
goto badframe;
if (restore_altstack(&frame->uc.uc_stack))
goto badframe;
return er0;
badframe:
force_sig(SIGSEGV, current);
return 0;
}
static int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
unsigned long mask)
{
int err = 0;
err |= __put_user(regs->er0, &sc->sc_er0);
err |= __put_user(regs->er1, &sc->sc_er1);
err |= __put_user(regs->er2, &sc->sc_er2);
err |= __put_user(regs->er3, &sc->sc_er3);
err |= __put_user(regs->er4, &sc->sc_er4);
err |= __put_user(regs->er5, &sc->sc_er5);
err |= __put_user(regs->er6, &sc->sc_er6);
err |= __put_user(rdusp(), &sc->sc_usp);
err |= __put_user(regs->pc, &sc->sc_pc);
err |= __put_user(regs->ccr, &sc->sc_ccr);
err |= __put_user(mask, &sc->sc_mask);
return err;
}
static inline void __user *
get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size)
{
return (void __user *)((sigsp(rdusp(), ksig) - frame_size) & -8UL);
}
static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
struct pt_regs *regs)
{
struct rt_sigframe *frame;
int err = 0;
unsigned char *ret;
frame = get_sigframe(ksig, regs, sizeof(*frame));
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;
if (ksig->ka.sa.sa_flags & SA_SIGINFO)
err |= copy_siginfo_to_user(&frame->info, &ksig->info);
/* Create the ucontext. */
err |= __put_user(0, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __save_altstack(&frame->uc.uc_stack, rdusp());
err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
return -EFAULT;
/* Set up to return from userspace. */
ret = frame->retcode;
if (ksig->ka.sa.sa_flags & SA_RESTORER)
ret = (unsigned char *)(ksig->ka.sa.sa_restorer);
else {
/* sub.l er0,er0; mov.b #__NR_rt_sigreturn,r0l; trapa #0 */
err |= __put_user(0x1a80f800 + (__NR_rt_sigreturn & 0xff),
(unsigned long *)(frame->retcode + 0));
err |= __put_user(0x5700,
(unsigned short *)(frame->retcode + 4));
}
err |= __put_user(ret, &frame->pretcode);
if (err)
return -EFAULT;
/* Set up registers for signal handler */
wrusp((unsigned long) frame);
regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
regs->er0 = ksig->sig;
regs->er1 = (unsigned long)&(frame->info);
regs->er2 = (unsigned long)&frame->uc;
regs->er5 = current->mm->start_data; /* GOT base */
return 0;
}
static void
handle_restart(struct pt_regs *regs, struct k_sigaction *ka)
{
switch (regs->er0) {
case -ERESTARTNOHAND:
if (!ka)
goto do_restart;
regs->er0 = -EINTR;
break;
case -ERESTART_RESTARTBLOCK:
if (!ka) {
regs->er0 = __NR_restart_syscall;
regs->pc -= 2;
} else
regs->er0 = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->er0 = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
do_restart:
regs->er0 = regs->orig_er0;
regs->pc -= 2;
break;
}
}
/*
* OK, we're invoking a handler
*/
static void
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
sigset_t *oldset = sigmask_to_save();
int ret;
/* are we from a system call? */
if (regs->orig_er0 >= 0)
handle_restart(regs, &ksig->ka);
ret = setup_rt_frame(ksig, oldset, regs);
signal_setup_done(ret, ksig, 0);
}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
* want to handle. Thus you cannot kill init even with a SIGKILL even by
* mistake.
*/
static void do_signal(struct pt_regs *regs)
{
struct ksignal ksig;
current->thread.esp0 = (unsigned long) regs;
if (get_signal(&ksig)) {
/* Whee! Actually deliver the signal. */
handle_signal(&ksig, regs);
return;
}
/* Did we come from a system call? */
if (regs->orig_er0 >= 0)
handle_restart(regs, NULL);
/* If there's no signal to deliver, we just restore the saved mask. */
restore_saved_sigmask();
}
asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags)
{
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
if (thread_info_flags & _TIF_NOTIFY_RESUME) {
clear_thread_flag(TIF_NOTIFY_RESUME);
tracehook_notify_resume(regs);
}
}
/*
* arch/h8300/kernel/early_printk.c
*
* Copyright (C) 2009 Yoshinori Sato <ysato@users.sourceforge.jp>
*
* 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/console.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
static void sim_write(struct console *co, const char *ptr,
unsigned len)
{
register const int fd __asm__("er0") = 1; /* stdout */
register const char *_ptr __asm__("er1") = ptr;
register const unsigned _len __asm__("er2") = len;
__asm__(".byte 0x5e,0x00,0x00,0xc7\n\t" /* jsr @0xc7 (sys_write) */
: : "g"(fd), "g"(_ptr), "g"(_len));
}
static struct console sim_console = {
.name = "sim_console",
.write = sim_write,
.setup = NULL,
.flags = CON_PRINTBUFFER,
.index = -1,
};
static char sim_console_buf[32];
static int sim_probe(struct platform_device *pdev)
{
if (sim_console.data)
return -EEXIST;
if (!strstr(sim_console_buf, "keep"))
sim_console.flags |= CON_BOOT;
register_console(&sim_console);
return 0;
}
static int sim_remove(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver sim_driver = {
.probe = sim_probe,
.remove = sim_remove,
.driver = {
.name = "h8300-sim",
.owner = THIS_MODULE,
},
};
early_platform_init_buffer("earlyprintk", &sim_driver,
sim_console_buf, ARRAY_SIZE(sim_console_buf));
static struct platform_device sim_console_device = {
.name = "h8300-sim",
.id = 0,
};
static struct platform_device *devices[] __initdata = {
&sim_console_device,
};
void __init sim_console_register(void)
{
early_platform_add_devices(devices,
ARRAY_SIZE(devices));
}
#include <linux/syscalls.h>
#include <linux/signal.h>
#include <linux/unistd.h>
#undef __SYSCALL
#define __SYSCALL(nr, call) [nr] = (call),
#define sys_mmap2 sys_mmap_pgoff
asmlinkage int sys_rt_sigreturn(void);
void *_sys_call_table[__NR_syscalls] = {
#include <asm/unistd.h>
};
/*
* linux/arch/h8300/boot/traps.c -- general exception handling code
* H8/300 support Yoshinori Sato <ysato@users.sourceforge.jp>
*
* Cloned from Linux/m68k.
*
* No original Copyright holder listed,
* Probable original (C) Roman Zippel (assigned DJD, 1999)
*
* Copyright 1999-2000 D. Jeff Dionne, <jeff@rt-control.com>
*
* 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/types.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/bug.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/page.h>
static DEFINE_SPINLOCK(die_lock);
/*
* this must be called very early as the kernel might
* use some instruction that are emulated on the 060
*/
void __init base_trap_init(void)
{
}
void __init trap_init(void)
{
}
asmlinkage void set_esp0(unsigned long ssp)
{
current->thread.esp0 = ssp;
}
/*
* Generic dumping code. Used for panic and debug.
*/
static void dump(struct pt_regs *fp)
{
unsigned long *sp;
unsigned char *tp;
int i;
pr_info("\nCURRENT PROCESS:\n\n");
pr_info("COMM=%s PID=%d\n", current->comm, current->pid);
if (current->mm) {
pr_info("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
(int) current->mm->start_code,
(int) current->mm->end_code,
(int) current->mm->start_data,
(int) current->mm->end_data,
(int) current->mm->end_data,
(int) current->mm->brk);
pr_info("USER-STACK=%08x KERNEL-STACK=%08lx\n\n",
(int) current->mm->start_stack,
(int) PAGE_SIZE+(unsigned long)current);
}
show_regs(fp);
pr_info("\nCODE:");
tp = ((unsigned char *) fp->pc) - 0x20;
for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
if ((i % 0x10) == 0)
pr_info("\n%08x: ", (int) (tp + i));
pr_info("%08x ", (int) *sp++);
}
pr_info("\n");
pr_info("\nKERNEL STACK:");
tp = ((unsigned char *) fp) - 0x40;
for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
if ((i % 0x10) == 0)
pr_info("\n%08x: ", (int) (tp + i));
pr_info("%08x ", (int) *sp++);
}
pr_info("\n");
if (STACK_MAGIC != *(unsigned long *)((unsigned long)current+PAGE_SIZE))
pr_info("(Possibly corrupted stack page??)\n");
pr_info("\n\n");
}
void die(const char *str, struct pt_regs *fp, unsigned long err)
{
static int diecount;
oops_enter();
console_verbose();
spin_lock_irq(&die_lock);
report_bug(fp->pc, fp);
pr_crit("%s: %04lx [#%d] ", str, err & 0xffff, ++diecount);
dump(fp);
spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
static int kstack_depth_to_print = 24;
void show_stack(struct task_struct *task, unsigned long *esp)
{
unsigned long *stack, addr;
int i;
if (esp == NULL)
esp = (unsigned long *) &esp;
stack = esp;
pr_info("Stack from %08lx:", (unsigned long)stack);
for (i = 0; i < kstack_depth_to_print; i++) {
if (((unsigned long)stack & (THREAD_SIZE - 1)) == 0)
break;
if (i % 8 == 0)
pr_info("\n ");
pr_info(" %08lx", *stack++);
}
pr_info("\nCall Trace:");
i = 0;
stack = esp;
while (((unsigned long)stack & (THREAD_SIZE - 1)) != 0) {
addr = *stack++;
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
* memory, it *may* be the address of a calling
* routine; if so, print it so that someone tracing
* down the cause of the crash will be able to figure
* out the call path that was taken.
*/
if (check_kernel_text(addr)) {
if (i % 4 == 0)
pr_info("\n ");
pr_info(" [<%08lx>]", addr);
i++;
}
}
pr_info("\n");
}
void show_trace_task(struct task_struct *tsk)
{
show_stack(tsk, (unsigned long *)tsk->thread.esp0);
}
#include <asm-generic/vmlinux.lds.h>
#include <asm/page.h>
#define ROMTOP 0x000000
#define RAMTOP 0x400000
jiffies = jiffies_64 + 4;
ENTRY(_start)
SECTIONS
{
#if defined(CONFIG_ROMKERNEL)
. = ROMTOP;
.vectors :
{
_vector = . ;
*(.vector*)
}
#else
. = RAMTOP;
_ramstart = .;
. = . + CONFIG_OFFSET;
#endif
_text = .;
HEAD_TEXT_SECTION
.text : {
_stext = . ;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
#if defined(CONFIG_ROMKERNEL)
*(.int_redirect)
#endif
_etext = . ;
}
EXCEPTION_TABLE(16)
NOTES
RO_DATA_SECTION(4)
ROMEND = .;
#if defined(CONFIG_ROMKERNEL)
. = RAMTOP;
_ramstart = .;
#define ADDR(x) ROMEND
#else
#endif
_sdata = . ;
__data_start = . ;
RW_DATA_SECTION(0,0,0)
#if defined(CONFIG_ROMKERNEL)
#undef ADDR
#endif
. = ALIGN(0x4) ;
__init_begin = .;
INIT_TEXT_SECTION(4)
INIT_DATA_SECTION(4)
SECURITY_INIT
__init_end = .;
_edata = . ;
_begin_data = LOADADDR(.data);
_sbss =.;
BSS_SECTION(0, 0 ,0)
_ebss =.;
_ramend = .;
_end = .;
DISCARDS
}
#
# Makefile for H8/300-specific library files..
#
lib-y = memcpy.o memset.o abs.o strncpy.o \
mulsi3.o udivsi3.o muldi3.o moddivsi3.o \
ashldi3.o lshrdi3.o ashrdi3.o ucmpdi2.o \
delay.o
;;; abs.S
#include <asm/linkage.h>
#if defined(CONFIG_CPU_H8300H)
.h8300h
#endif
#if defined(CONFIG_CPU_H8S)
.h8300s
#endif
.text
.global _abs
;;; int abs(int n)
_abs:
mov.l er0,er0
bpl 1f
neg.l er0
1:
rts
#include "libgcc.h"
DWtype
__ashldi3(DWtype u, word_type b)
{
const DWunion uu = {.ll = u};
const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
DWunion w;
if (b == 0)
return u;
if (bm <= 0) {
w.s.low = 0;
w.s.high = (UWtype) uu.s.low << -bm;
} else {
const UWtype carries = (UWtype) uu.s.low >> bm;
w.s.low = (UWtype) uu.s.low << b;
w.s.high = ((UWtype) uu.s.high << b) | carries;
}
return w.ll;
}
#include "libgcc.h"
DWtype __ashrdi3(DWtype u, word_type b)
{
const DWunion uu = {.ll = u};
const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
DWunion w;
if (b == 0)
return u;
if (bm <= 0) {
/* w.s.high = 1..1 or 0..0 */
w.s.high = uu.s.high >> (sizeof (Wtype) * BITS_PER_UNIT - 1);
w.s.low = uu.s.high >> -bm;
} else {
const UWtype carries = (UWtype) uu.s.high << bm;
w.s.high = uu.s.high >> b;
w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
}
/*
* delay loops
*
* Copyright (C) 2015 Yoshinori Sato
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <asm/param.h>
#include <asm/processor.h>
#include <asm/timex.h>
void __delay(unsigned long cycles)
{
__asm__ volatile ("1: dec.l #1,%0\n\t"
"bne 1b":"=r"(cycles):"0"(cycles));
}
EXPORT_SYMBOL(__delay);
void __const_udelay(unsigned long xloops)
{
u64 loops;
loops = (u64)xloops * loops_per_jiffy * HZ;
__delay(loops >> 32);
}
EXPORT_SYMBOL(__const_udelay);
void __udelay(unsigned long usecs)
{
__const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
}
EXPORT_SYMBOL(__udelay);
void __ndelay(unsigned long nsecs)
{
__const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
}
EXPORT_SYMBOL(__ndelay);
#ifndef __H8300_LIBGCC_H__
#define __H8300_LIBGCC_H__
#ifdef __ASSEMBLY__
#define A0 r0
#define A0L r0l
#define A0H r0h
#define A1 r1
#define A1L r1l
#define A1H r1h
#define A2 r2
#define A2L r2l
#define A2H r2h
#define A3 r3
#define A3L r3l
#define A3H r3h
#define S0 r4
#define S0L r4l
#define S0H r4h
#define S1 r5
#define S1L r5l
#define S1H r5h
#define S2 r6
#define S2L r6l
#define S2H r6h
#define PUSHP push.l
#define POPP pop.l
#define A0P er0
#define A1P er1
#define A2P er2
#define A3P er3
#define S0P er4
#define S1P er5
#define S2P er6
#define A0E e0
#define A1E e1
#define A2E e2
#define A3E e3
#else
#define Wtype SItype
#define UWtype USItype
#define HWtype SItype
#define UHWtype USItype
#define DWtype DItype
#define UDWtype UDItype
#define UWtype USItype
#define Wtype SItype
#define UWtype USItype
#define W_TYPE_SIZE (4 * BITS_PER_UNIT)
#define BITS_PER_UNIT (8)
typedef int SItype __attribute__ ((mode (SI)));
typedef unsigned int USItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
typedef unsigned int UDItype __attribute__ ((mode (DI)));
struct DWstruct {
Wtype high, low;
};
typedef union {
struct DWstruct s;
DWtype ll;
} DWunion;
typedef int word_type __attribute__ ((mode (__word__)));
#endif
#endif
#include "libgcc.h"
DWtype __lshrdi3(DWtype u, word_type b)
{
const DWunion uu = {.ll = u};
const word_type bm = (sizeof (Wtype) * BITS_PER_UNIT) - b;
DWunion w;
if (b == 0)
return u;
if (bm <= 0) {
w.s.high = 0;
w.s.low = (UWtype) uu.s.high >> -bm;
} else {
const UWtype carries = (UWtype) uu.s.high << bm;
w.s.high = (UWtype) uu.s.high >> b;
w.s.low = ((UWtype) uu.s.low >> b) | carries;
}
return w.ll;
}
;;; memcpy.S
#include <asm/linkage.h>
#if defined(CONFIG_CPU_H8300H)
.h8300h
#endif
#if defined(CONFIG_CPU_H8S)
.h8300s
#endif
.text
.global memcpy
;;; void *memcpy(void *to, void *from, size_t n)
memcpy:
mov.l er2,er2
bne 1f
rts
1:
;; address check
bld #0,r0l
bxor #0,r1l
bcs 4f
mov.l er4,@-sp
mov.l er0,@-sp
btst #0,r0l
beq 1f
;; (aligned even) odd address
mov.b @er1,r3l
mov.b r3l,@er0
adds #1,er1
adds #1,er0
dec.l #1,er2
beq 3f
1:
;; n < sizeof(unsigned long) check
sub.l er4,er4
adds #4,er4 ; loop count check value
cmp.l er4,er2
blo 2f
;; unsigned long copy
1:
mov.l @er1,er3
mov.l er3,@er0
adds #4,er0
adds #4,er1
subs #4,er2
cmp.l er4,er2
bcc 1b
;; rest
2:
mov.l er2,er2
beq 3f
1:
mov.b @er1,r3l
mov.b r3l,@er0
adds #1,er1
adds #1,er0
dec.l #1,er2
bne 1b
3:
mov.l @sp+,er0
mov.l @sp+,er4
rts
;; odd <- even / even <- odd
4:
mov.l er4,er3
mov.l er2,er4
mov.l er5,er2
mov.l er1,er5
mov.l er6,er1
mov.l er0,er6
1:
eepmov.w
mov.w r4,r4
bne 1b
dec.w #1,e4
bpl 1b
mov.l er1,er6
mov.l er2,er5
mov.l er3,er4
rts
.end
/* memset.S */
#include <asm/linkage.h>
#if defined(CONFIG_CPU_H8300H)
.h8300h
#endif
#if defined(CONFIG_CPU_H8S)
.h8300s
#endif
.text
.global memset
.global clear_user
;;void *memset(*ptr, int c, size_t count)
;; ptr = er0
;; c = er1(r1l)
;; count = er2
memset:
btst #0,r0l
beq 2f
;; odd address
1:
mov.b r1l,@er0
adds #1,er0
dec.l #1,er2
beq 6f
;; even address
2:
mov.l er2,er3
cmp.l #4,er2
blo 4f
;; count>=4 -> count/4
#if defined(CONFIG_CPU_H8300H)
shlr.l er2
shlr.l er2
#endif
#if defined(CONFIG_CPU_H8S)
shlr.l #2,er2
#endif
;; byte -> long
mov.b r1l,r1h
mov.w r1,e1
3:
mov.l er1,@er0
adds #4,er0
dec.l #1,er2
bne 3b
4:
;; count % 4
and.b #3,r3l
beq 6f
5:
mov.b r1l,@er0
adds #1,er0
dec.b r3l
bne 5b
6:
rts
clear_user:
mov.l er1, er2
sub.l er1, er1
bra memset
.end
#include "libgcc.h"
; numerator in A0/A1
; denominator in A2/A3
.global __modsi3
__modsi3:
PUSHP S2P
bsr modnorm
bsr __divsi3
mov.l er3,er0
bra exitdiv
.global __umodsi3
__umodsi3:
bsr __udivsi3:16
mov.l er3,er0
rts
.global __divsi3
__divsi3:
PUSHP S2P
bsr divnorm
bsr __udivsi3:16
; examine what the sign should be
exitdiv:
btst #3,S2L
beq reti
; should be -ve
neg.l A0P
reti:
POPP S2P
rts
divnorm:
mov.l A0P,A0P ; is the numerator -ve
stc ccr,S2L ; keep the sign in bit 3 of S2L
bge postive
neg.l A0P ; negate arg
postive:
mov.l A1P,A1P ; is the denominator -ve
bge postive2
neg.l A1P ; negate arg
xor.b #0x08,S2L ; toggle the result sign
postive2:
rts
;; Basically the same, except that the sign of the divisor determines
;; the sign.
modnorm:
mov.l A0P,A0P ; is the numerator -ve
stc ccr,S2L ; keep the sign in bit 3 of S2L
bge mpostive
neg.l A0P ; negate arg
mpostive:
mov.l A1P,A1P ; is the denominator -ve
bge mpostive2
neg.l A1P ; negate arg
mpostive2:
rts
.end
#include "libgcc.h"
; numerator in A0/A1
; denominator in A2/A3
.global __modsi3
__modsi3:
PUSHP S2P
bsr modnorm
bsr __divsi3
mov.l er3,er0
bra exitdiv
.global __umodsi3
__umodsi3:
bsr __udivsi3
mov.l er3,er0
rts
.global __divsi3
__divsi3:
PUSHP S2P
jsr divnorm
bsr __udivsi3
; examine what the sign should be
exitdiv:
btst #3,S2L
beq reti
; should be -ve
neg.l A0P
reti:
POPP S2P
rts
divnorm:
mov.l A0P,A0P ; is the numerator -ve
stc ccr,S2L ; keep the sign in bit 3 of S2L
bge postive
neg.l A0P ; negate arg
postive:
mov.l A1P,A1P ; is the denominator -ve
bge postive2
neg.l A1P ; negate arg
xor.b #0x08,S2L ; toggle the result sign
postive2:
rts
;; Basically the same, except that the sign of the divisor determines
;; the sign.
modnorm:
mov.l A0P,A0P ; is the numerator -ve
stc ccr,S2L ; keep the sign in bit 3 of S2L
bge mpostive
neg.l A0P ; negate arg
mpostive:
mov.l A1P,A1P ; is the denominator -ve
bge mpostive2
neg.l A1P ; negate arg
mpostive2:
rts
.end
#include "libgcc.h"
#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
#define umul_ppmm(w1, w0, u, v) \
do { \
UWtype __x0, __x1, __x2, __x3; \
UHWtype __ul, __vl, __uh, __vh; \
__ul = __ll_lowpart(u); \
__uh = __ll_highpart(u); \
__vl = __ll_lowpart(v); \
__vh = __ll_highpart(v); \
__x0 = (UWtype) __ul * __vl; \
__x1 = (UWtype) __ul * __vh; \
__x2 = (UWtype) __uh * __vl; \
__x3 = (UWtype) __uh * __vh; \
__x1 += __ll_highpart(__x0); \
__x1 += __x2; \
if (__x1 < __x2) \
__x3 += __ll_B; \
(w1) = __x3 + __ll_highpart(__x1); \
(w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0); \
} while (0)
#define __umulsidi3(u, v) ( \
{ \
DWunion __w; \
umul_ppmm(__w.s.high, __w.s.low, u, v); \
__w.ll; } \
)
DWtype __muldi3(DWtype u, DWtype v)
{
const DWunion uu = {.ll = u};
const DWunion vv = {.ll = v};
DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)};
w.s.high += ((UWtype) uu.s.low * (UWtype) vv.s.high
+ (UWtype) uu.s.high * (UWtype) vv.s.low);
return w.ll;
}
;
; mulsi3 for H8/300H - based on Renesas SH implementation
;
; by Toshiyasu Morita
;
; Old code:
;
; 16b * 16b = 372 states (worst case)
; 32b * 32b = 724 states (worst case)
;
; New code:
;
; 16b * 16b = 48 states
; 16b * 32b = 72 states
; 32b * 32b = 92 states
;
.global __mulsi3
__mulsi3:
mov.w r1,r2 ; ( 2 states) b * d
mulxu r0,er2 ; (22 states)
mov.w e0,r3 ; ( 2 states) a * d
beq L_skip1 ; ( 4 states)
mulxu r1,er3 ; (22 states)
add.w r3,e2 ; ( 2 states)
L_skip1:
mov.w e1,r3 ; ( 2 states) c * b
beq L_skip2 ; ( 4 states)
mulxu r0,er3 ; (22 states)
add.w r3,e2 ; ( 2 states)
L_skip2:
mov.l er2,er0 ; ( 2 states)
rts ; (10 states)
.end
;;; strncpy.S
#include <asm/linkage.h>
.text
.global strncpy_from_user
;;; long strncpy_from_user(void *to, void *from, size_t n)
strncpy_from_user:
mov.l er2,er2
bne 1f
sub.l er0,er0
rts
1:
mov.l er4,@-sp
sub.l er3,er3
2:
mov.b @er1+,r4l
mov.b r4l,@er0
adds #1,er0
beq 3f
inc.l #1,er3
dec.l #1,er2
bne 2b
3:
dec.l #1,er2
4:
mov.b r4l,@er0
adds #1,er0
dec.l #1,er2
bne 4b
mov.l er3,er0
mov.l @sp+,er4
rts
#include "libgcc.h"
word_type __ucmpdi2(DWtype a, DWtype b)
{
const DWunion au = {.ll = a};
const DWunion bu = {.ll = b};
if ((UWtype) au.s.high < (UWtype) bu.s.high)
return 0;
else if ((UWtype) au.s.high > (UWtype) bu.s.high)
return 2;
if ((UWtype) au.s.low < (UWtype) bu.s.low)
return 0;
else if ((UWtype) au.s.low > (UWtype) bu.s.low)
return 2;
return 1;
}
#include "libgcc.h"
;; This function also computes the remainder and stores it in er3.
.global __udivsi3
__udivsi3:
mov.w A1E,A1E ; denominator top word 0?
bne DenHighNonZero
; do it the easy way, see page 107 in manual
mov.w A0E,A2
extu.l A2P
divxu.w A1,A2P
mov.w A2E,A0E
divxu.w A1,A0P
mov.w A0E,A3
mov.w A2,A0E
extu.l A3P
rts
; er0 = er0 / er1
; er3 = er0 % er1
; trashes er1 er2
; expects er1 >= 2^16
DenHighNonZero:
mov.l er0,er3
mov.l er1,er2
#ifdef CONFIG_CPU_H8300H
divmod_L21:
shlr.l er0
shlr.l er2 ; make divisor < 2^16
mov.w e2,e2
bne divmod_L21
#else
shlr.l #2,er2 ; make divisor < 2^16
mov.w e2,e2
beq divmod_L22A
divmod_L21:
shlr.l #2,er0
divmod_L22:
shlr.l #2,er2 ; make divisor < 2^16
mov.w e2,e2
bne divmod_L21
divmod_L22A:
rotxl.w r2
bcs divmod_L23
shlr.l er0
bra divmod_L24
divmod_L23:
rotxr.w r2
shlr.l #2,er0
divmod_L24:
#endif
;; At this point,
;; er0 contains shifted dividend
;; er1 contains divisor
;; er2 contains shifted divisor
;; er3 contains dividend, later remainder
divxu.w r2,er0 ; r0 now contains the approximate quotient (AQ)
extu.l er0
beq divmod_L25
subs #1,er0 ; er0 = AQ - 1
mov.w e1,r2
mulxu.w r0,er2 ; er2 = upper (AQ - 1) * divisor
sub.w r2,e3 ; dividend - 65536 * er2
mov.w r1,r2
mulxu.w r0,er2 ; compute er3 = remainder (tentative)
sub.l er2,er3 ; er3 = dividend - (AQ - 1) * divisor
divmod_L25:
cmp.l er1,er3 ; is divisor < remainder?
blo divmod_L26
adds #1,er0
sub.l er1,er3 ; correct the remainder
divmod_L26:
rts
.end
#
# Makefile for the linux h8300-specific parts of the memory manager.
#
obj-y := init.o fault.o memory.o
/*
* linux/arch/h8300/mm/fault.c
*
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
* Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
*
* Based on:
*
* linux/arch/m68knommu/mm/fault.c
* linux/arch/m68k/mm/fault.c
*
* Copyright (C) 1995 Hamish Macdonald
*/
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <asm/pgtable.h>
void die(const char *str, struct pt_regs *fp, unsigned long err);
/*
* This routine handles page faults. It determines the problem, and
* then passes it off to one of the appropriate routines.
*
* error_code:
* bit 0 == 0 means no page found, 1 means protection fault
* bit 1 == 0 means read, 1 means write
*
* If this routine detects a bad access, it returns 1, otherwise it
* returns 0.
*/
asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
unsigned long error_code)
{
#ifdef DEBUG
pr_debug("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld\n",
regs->sr, regs->pc, address, error_code);
#endif
/*
* Oops. The kernel tried to access some bad page. We'll have to
* terminate things with extreme prejudice.
*/
if ((unsigned long) address < PAGE_SIZE)
pr_alert("Unable to handle kernel NULL pointer dereference");
else
pr_alert("Unable to handle kernel access");
printk(" at virtual address %08lx\n", address);
if (!user_mode(regs))
die("Oops", regs, error_code);
do_exit(SIGKILL);
return 1;
}
/*
* linux/arch/h8300/mm/init.c
*
* Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
* Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 2000 Lineo, Inc. (www.lineo.com)
*
* Based on:
*
* linux/arch/m68knommu/mm/init.c
* linux/arch/m68k/mm/init.c
*
* Copyright (C) 1995 Hamish Macdonald
*
* JAN/1999 -- hacked to support ColdFire (gerg@snapgear.com)
* DEC/2000 -- linux 2.4 support <davidm@snapgear.com>
*/
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/ptrace.h>
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/init.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/bootmem.h>
#include <linux/gfp.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/sections.h>
/*
* BAD_PAGE is the page that is used for page faults when linux
* is out-of-memory. Older versions of linux just did a
* do_exit(), but using this instead means there is less risk
* for a process dying in kernel mode, possibly leaving a inode
* unused etc..
*
* BAD_PAGETABLE is the accompanying page-table: it is initialized
* to point to BAD_PAGE entries.
*
* ZERO_PAGE is a special page that is used for zero-initialized
* data and COW.
*/
static unsigned long empty_bad_page_table;
static unsigned long empty_bad_page;
unsigned long empty_zero_page;
/*
* paging_init() continues the virtual memory environment setup which
* was begun by the code in arch/head.S.
* The parameters are pointers to where to stick the starting and ending
* addresses of available kernel virtual memory.
*/
void __init paging_init(void)
{
/*
* Make sure start_mem is page aligned, otherwise bootmem and
* page_alloc get different views og the world.
*/
unsigned long start_mem = PAGE_ALIGN(memory_start);
unsigned long end_mem = memory_end & PAGE_MASK;
pr_debug("start_mem is %#lx\nvirtual_end is %#lx\n",
start_mem, end_mem);
/*
* Initialize the bad page table and bad page to point
* to a couple of allocated pages.
*/
empty_bad_page_table = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
empty_bad_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
empty_zero_page = (unsigned long)alloc_bootmem_pages(PAGE_SIZE);
memset((void *)empty_zero_page, 0, PAGE_SIZE);
/*
* Set up SFC/DFC registers (user data space).
*/
set_fs(USER_DS);
pr_debug("before free_area_init\n");
pr_debug("free_area_init -> start_mem is %#lx\nvirtual_end is %#lx\n",
start_mem, end_mem);
{
unsigned long zones_size[MAX_NR_ZONES] = {0, };
zones_size[ZONE_NORMAL] = (end_mem - PAGE_OFFSET) >> PAGE_SHIFT;
free_area_init(zones_size);
}
}
void __init mem_init(void)
{
pr_devel("Mem_init: start=%lx, end=%lx\n", memory_start, memory_end);
high_memory = (void *) (memory_end & PAGE_MASK);
max_mapnr = MAP_NR(high_memory);
/* this will put all low memory onto the freelists */
free_all_bootmem();
mem_init_print_info(NULL);
}
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
{
free_reserved_area((void *)start, (void *)end, -1, "initrd");
}
#endif
void
free_initmem(void)
{
free_initmem_default(-1);
}
/*
* linux/arch/h8300/mm/memory.c
*
* Copyright (C) 2002 Yoshinori Sato <ysato@users.sourceforge.jp>,
*
* Based on:
*
* linux/arch/m68knommu/mm/memory.c
*
* Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>,
* Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
*
* Based on:
*
* linux/arch/m68k/mm/memory.c
*
* Copyright (C) 1995 Hamish Macdonald
*/
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/types.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/traps.h>
#include <asm/io.h>
void cache_clear(unsigned long paddr, int len)
{
}
void cache_push(unsigned long paddr, int len)
{
}
void cache_push_v(unsigned long vaddr, int len)
{
}
/*
* Map some physical address range into the kernel address space.
*/
unsigned long kernel_map(unsigned long paddr, unsigned long size,
int nocacheflag, unsigned long *memavailp)
{
return paddr;
}
...@@ -73,3 +73,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/ ...@@ -73,3 +73,4 @@ obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
obj-$(CONFIG_X86) += x86/ obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_ARCH_ZYNQ) += zynq/ obj-$(CONFIG_ARCH_ZYNQ) += zynq/
obj-$(CONFIG_H8300) += h8300/
obj-y += clk-div.o
obj-$(CONFIG_H8S2678) += clk-h8s2678.o
/*
* H8/300 divide clock driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_address.h>
static DEFINE_SPINLOCK(clklock);
static void __init h8300_div_clk_setup(struct device_node *node)
{
unsigned int num_parents;
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
void __iomem *divcr = NULL;
int width;
num_parents = of_clk_get_parent_count(node);
if (num_parents < 1) {
pr_err("%s: no parent found", clk_name);
return;
}
divcr = of_iomap(node, 0);
if (divcr == NULL) {
pr_err("%s: failed to map divide register", clk_name);
goto error;
}
parent_name = of_clk_get_parent_name(node, 0);
of_property_read_u32(node, "renesas,width", &width);
clk = clk_register_divider(NULL, clk_name, parent_name,
CLK_SET_RATE_GATE, divcr, 0, width,
CLK_DIVIDER_POWER_OF_TWO, &clklock);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
return;
}
pr_err("%s: failed to register %s div clock (%ld)\n",
__func__, clk_name, PTR_ERR(clk));
error:
if (divcr)
iounmap(divcr);
}
CLK_OF_DECLARE(h8300_div_clk, "renesas,h8300-div-clock", h8300_div_clk_setup);
/*
* H8S2678 clock driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/of_address.h>
static DEFINE_SPINLOCK(clklock);
#define MAX_FREQ 33333333
#define MIN_FREQ 8000000
struct pll_clock {
struct clk_hw hw;
void __iomem *sckcr;
void __iomem *pllcr;
};
#define to_pll_clock(_hw) container_of(_hw, struct pll_clock, hw)
static unsigned long pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct pll_clock *pll_clock = to_pll_clock(hw);
int mul = 1 << (ctrl_inb((unsigned long)pll_clock->pllcr) & 3);
return parent_rate * mul;
}
static long pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int i, m = -1;
long offset[3];
if (rate > MAX_FREQ)
rate = MAX_FREQ;
if (rate < MIN_FREQ)
rate = MIN_FREQ;
for (i = 0; i < 3; i++)
offset[i] = abs(rate - (*prate * (1 << i)));
for (i = 0; i < 3; i++)
if (m < 0)
m = i;
else
m = (offset[i] < offset[m])?i:m;
return *prate * (1 << m);
}
static int pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
int pll;
unsigned char val;
unsigned long flags;
struct pll_clock *pll_clock = to_pll_clock(hw);
pll = ((rate / parent_rate) / 2) & 0x03;
spin_lock_irqsave(&clklock, flags);
val = ctrl_inb((unsigned long)pll_clock->sckcr);
val |= 0x08;
ctrl_outb(val, (unsigned long)pll_clock->sckcr);
val = ctrl_inb((unsigned long)pll_clock->pllcr);
val &= ~0x03;
val |= pll;
ctrl_outb(val, (unsigned long)pll_clock->pllcr);
spin_unlock_irqrestore(&clklock, flags);
return 0;
}
static const struct clk_ops pll_ops = {
.recalc_rate = pll_recalc_rate,
.round_rate = pll_round_rate,
.set_rate = pll_set_rate,
};
static void __init h8s2678_pll_clk_setup(struct device_node *node)
{
unsigned int num_parents;
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
struct pll_clock *pll_clock;
struct clk_init_data init;
num_parents = of_clk_get_parent_count(node);
if (num_parents < 1) {
pr_err("%s: no parent found", clk_name);
return;
}
pll_clock = kzalloc(sizeof(struct pll_clock), GFP_KERNEL);
if (!pll_clock) {
pr_err("%s: failed to alloc memory", clk_name);
return;
}
pll_clock->sckcr = of_iomap(node, 0);
if (pll_clock->sckcr == NULL) {
pr_err("%s: failed to map divide register", clk_name);
goto free_clock;
}
pll_clock->pllcr = of_iomap(node, 1);
if (pll_clock->pllcr == NULL) {
pr_err("%s: failed to map multiply register", clk_name);
goto unmap_sckcr;
}
parent_name = of_clk_get_parent_name(node, 0);
init.name = clk_name;
init.ops = &pll_ops;
init.flags = CLK_IS_BASIC;
init.parent_names = &parent_name;
init.num_parents = 1;
pll_clock->hw.init = &init;
clk = clk_register(NULL, &pll_clock->hw);
if (IS_ERR(clk)) {
pr_err("%s: failed to register %s div clock (%ld)\n",
__func__, clk_name, PTR_ERR(clk));
goto unmap_pllcr;
}
of_clk_add_provider(node, of_clk_src_simple_get, clk);
return;
unmap_pllcr:
iounmap(pll_clock->pllcr);
unmap_sckcr:
iounmap(pll_clock->sckcr);
free_clock:
kfree(pll_clock);
}
CLK_OF_DECLARE(h8s2678_div_clk, "renesas,h8s2678-pll-clock",
h8s2678_pll_clk_setup);
...@@ -275,4 +275,11 @@ config CLKSRC_PXA ...@@ -275,4 +275,11 @@ config CLKSRC_PXA
help help
This enables OST0 support available on PXA and SA-11x0 This enables OST0 support available on PXA and SA-11x0
platforms. platforms.
config H8300_TMR16
bool
config H8300_TPU
bool
endmenu endmenu
...@@ -55,3 +55,6 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o ...@@ -55,3 +55,6 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
obj-$(CONFIG_H8300) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
/*
* H8/300 16bit Timer driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/clocksource.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <asm/segment.h>
#include <asm/irq.h>
#define TSTR 0
#define TSNC 1
#define TMDR 2
#define TOLR 3
#define TISRA 4
#define TISRB 5
#define TISRC 6
#define TCR 0
#define TIOR 1
#define TCNT 2
#define GRA 4
#define GRB 6
#define FLAG_REPROGRAM (1 << 0)
#define FLAG_SKIPEVENT (1 << 1)
#define FLAG_IRQCONTEXT (1 << 2)
#define FLAG_STARTED (1 << 3)
#define ONESHOT 0
#define PERIODIC 1
#define RELATIVE 0
#define ABSOLUTE 1
struct timer16_priv {
struct platform_device *pdev;
struct clocksource cs;
struct irqaction irqaction;
unsigned long total_cycles;
unsigned long mapbase;
unsigned long mapcommon;
unsigned long flags;
unsigned short gra;
unsigned short cs_enabled;
unsigned char enb;
unsigned char imfa;
unsigned char imiea;
unsigned char ovf;
raw_spinlock_t lock;
struct clk *clk;
};
static unsigned long timer16_get_counter(struct timer16_priv *p)
{
unsigned long v1, v2, v3;
int o1, o2;
o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
o2 = o1;
v1 = ctrl_inw(p->mapbase + TCNT);
v2 = ctrl_inw(p->mapbase + TCNT);
v3 = ctrl_inw(p->mapbase + TCNT);
o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
v2 |= 0x10000;
return v2;
}
static irqreturn_t timer16_interrupt(int irq, void *dev_id)
{
struct timer16_priv *p = (struct timer16_priv *)dev_id;
ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
p->mapcommon + TISRA);
p->total_cycles += 0x10000;
return IRQ_HANDLED;
}
static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
{
return container_of(cs, struct timer16_priv, cs);
}
static cycle_t timer16_clocksource_read(struct clocksource *cs)
{
struct timer16_priv *p = cs_to_priv(cs);
unsigned long flags, raw;
unsigned long value;
raw_spin_lock_irqsave(&p->lock, flags);
value = p->total_cycles;
raw = timer16_get_counter(p);
raw_spin_unlock_irqrestore(&p->lock, flags);
return value + raw;
}
static int timer16_enable(struct clocksource *cs)
{
struct timer16_priv *p = cs_to_priv(cs);
WARN_ON(p->cs_enabled);
p->total_cycles = 0;
ctrl_outw(0x0000, p->mapbase + TCNT);
ctrl_outb(0x83, p->mapbase + TCR);
ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
p->mapcommon + TSTR);
p->cs_enabled = true;
return 0;
}
static void timer16_disable(struct clocksource *cs)
{
struct timer16_priv *p = cs_to_priv(cs);
WARN_ON(!p->cs_enabled);
ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
p->mapcommon + TSTR);
p->cs_enabled = false;
}
#define REG_CH 0
#define REG_COMM 1
static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
{
struct resource *res[2];
int ret, irq;
unsigned int ch;
memset(p, 0, sizeof(*p));
p->pdev = pdev;
res[REG_CH] = platform_get_resource(p->pdev,
IORESOURCE_MEM, REG_CH);
res[REG_COMM] = platform_get_resource(p->pdev,
IORESOURCE_MEM, REG_COMM);
if (!res[REG_CH] || !res[REG_COMM]) {
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
return -ENXIO;
}
irq = platform_get_irq(p->pdev, 0);
if (irq < 0) {
dev_err(&p->pdev->dev, "failed to get irq\n");
return irq;
}
p->clk = clk_get(&p->pdev->dev, "fck");
if (IS_ERR(p->clk)) {
dev_err(&p->pdev->dev, "can't get clk\n");
return PTR_ERR(p->clk);
}
of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
p->pdev = pdev;
p->mapbase = res[REG_CH]->start;
p->mapcommon = res[REG_COMM]->start;
p->enb = 1 << ch;
p->imfa = 1 << ch;
p->imiea = 1 << (4 + ch);
p->cs.name = pdev->name;
p->cs.rating = 200;
p->cs.read = timer16_clocksource_read;
p->cs.enable = timer16_enable;
p->cs.disable = timer16_disable;
p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
ret = request_irq(irq, timer16_interrupt,
IRQF_TIMER, pdev->name, p);
if (ret < 0) {
dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
return ret;
}
clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
return 0;
}
static int timer16_probe(struct platform_device *pdev)
{
struct timer16_priv *p = platform_get_drvdata(pdev);
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
return timer16_setup(p, pdev);
}
static int timer16_remove(struct platform_device *pdev)
{
return -EBUSY;
}
static const struct of_device_id timer16_of_table[] = {
{ .compatible = "renesas,16bit-timer" },
{ }
};
static struct platform_driver timer16_driver = {
.probe = timer16_probe,
.remove = timer16_remove,
.driver = {
.name = "h8300h-16timer",
.of_match_table = of_match_ptr(timer16_of_table),
}
};
static int __init timer16_init(void)
{
return platform_driver_register(&timer16_driver);
}
static void __exit timer16_exit(void)
{
platform_driver_unregister(&timer16_driver);
}
subsys_initcall(timer16_init);
module_exit(timer16_exit);
MODULE_AUTHOR("Yoshinori Sato");
MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
MODULE_LICENSE("GPL v2");
/*
* linux/arch/h8300/kernel/cpu/timer/timer8.c
*
* Yoshinori Sato <ysato@users.sourcefoge.jp>
*
* 8bit Timer driver
*
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clockchips.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <asm/irq.h>
#define _8TCR 0
#define _8TCSR 2
#define TCORA 4
#define TCORB 6
#define _8TCNT 8
#define FLAG_REPROGRAM (1 << 0)
#define FLAG_SKIPEVENT (1 << 1)
#define FLAG_IRQCONTEXT (1 << 2)
#define FLAG_STARTED (1 << 3)
#define ONESHOT 0
#define PERIODIC 1
#define RELATIVE 0
#define ABSOLUTE 1
struct timer8_priv {
struct platform_device *pdev;
struct clock_event_device ced;
struct irqaction irqaction;
unsigned long mapbase;
raw_spinlock_t lock;
unsigned long flags;
unsigned int rate;
unsigned int tcora;
struct clk *pclk;
};
static unsigned long timer8_get_counter(struct timer8_priv *p)
{
unsigned long v1, v2, v3;
int o1, o2;
o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
o2 = o1;
v1 = ctrl_inw(p->mapbase + _8TCNT);
v2 = ctrl_inw(p->mapbase + _8TCNT);
v3 = ctrl_inw(p->mapbase + _8TCNT);
o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
v2 |= o1 << 10;
return v2;
}
static irqreturn_t timer8_interrupt(int irq, void *dev_id)
{
struct timer8_priv *p = dev_id;
ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
p->mapbase + _8TCSR);
p->flags |= FLAG_IRQCONTEXT;
ctrl_outw(p->tcora, p->mapbase + TCORA);
if (!(p->flags & FLAG_SKIPEVENT)) {
if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
ctrl_outw(0x0000, p->mapbase + _8TCR);
p->ced.event_handler(&p->ced);
}
p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
return IRQ_HANDLED;
}
static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
{
unsigned long flags;
unsigned long now;
raw_spin_lock_irqsave(&p->lock, flags);
if (delta >= 0x10000)
dev_warn(&p->pdev->dev, "delta out of range\n");
now = timer8_get_counter(p);
p->tcora = delta;
ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
if (delta > now)
ctrl_outw(delta, p->mapbase + TCORA);
else
ctrl_outw(now + 1, p->mapbase + TCORA);
raw_spin_unlock_irqrestore(&p->lock, flags);
}
static int timer8_enable(struct timer8_priv *p)
{
p->rate = clk_get_rate(p->pclk) / 64;
ctrl_outw(0xffff, p->mapbase + TCORA);
ctrl_outw(0x0000, p->mapbase + _8TCNT);
ctrl_outw(0x0c02, p->mapbase + _8TCR);
return 0;
}
static int timer8_start(struct timer8_priv *p)
{
int ret = 0;
unsigned long flags;
raw_spin_lock_irqsave(&p->lock, flags);
if (!(p->flags & FLAG_STARTED))
ret = timer8_enable(p);
if (ret)
goto out;
p->flags |= FLAG_STARTED;
out:
raw_spin_unlock_irqrestore(&p->lock, flags);
return ret;
}
static void timer8_stop(struct timer8_priv *p)
{
unsigned long flags;
raw_spin_lock_irqsave(&p->lock, flags);
ctrl_outw(0x0000, p->mapbase + _8TCR);
raw_spin_unlock_irqrestore(&p->lock, flags);
}
static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
{
return container_of(ced, struct timer8_priv, ced);
}
static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
{
struct clock_event_device *ced = &p->ced;
timer8_start(p);
ced->shift = 32;
ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
}
static void timer8_clock_event_mode(enum clock_event_mode mode,
struct clock_event_device *ced)
{
struct timer8_priv *p = ced_to_priv(ced);
switch (mode) {
case CLOCK_EVT_MODE_PERIODIC:
dev_info(&p->pdev->dev, "used for periodic clock events\n");
timer8_stop(p);
timer8_clock_event_start(p, PERIODIC);
break;
case CLOCK_EVT_MODE_ONESHOT:
dev_info(&p->pdev->dev, "used for oneshot clock events\n");
timer8_stop(p);
timer8_clock_event_start(p, ONESHOT);
break;
case CLOCK_EVT_MODE_SHUTDOWN:
case CLOCK_EVT_MODE_UNUSED:
timer8_stop(p);
break;
default:
break;
}
}
static int timer8_clock_event_next(unsigned long delta,
struct clock_event_device *ced)
{
struct timer8_priv *p = ced_to_priv(ced);
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
timer8_set_next(p, delta - 1);
return 0;
}
static int timer8_setup(struct timer8_priv *p,
struct platform_device *pdev)
{
struct resource *res;
int irq;
int ret;
memset(p, 0, sizeof(*p));
p->pdev = pdev;
res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
return -ENXIO;
}
irq = platform_get_irq(p->pdev, 0);
if (irq < 0) {
dev_err(&p->pdev->dev, "failed to get irq\n");
return -ENXIO;
}
p->mapbase = res->start;
p->irqaction.name = dev_name(&p->pdev->dev);
p->irqaction.handler = timer8_interrupt;
p->irqaction.dev_id = p;
p->irqaction.flags = IRQF_TIMER;
p->pclk = clk_get(&p->pdev->dev, "fck");
if (IS_ERR(p->pclk)) {
dev_err(&p->pdev->dev, "can't get clk\n");
return PTR_ERR(p->pclk);
}
p->ced.name = pdev->name;
p->ced.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT;
p->ced.rating = 200;
p->ced.cpumask = cpumask_of(0);
p->ced.set_next_event = timer8_clock_event_next;
p->ced.set_mode = timer8_clock_event_mode;
ret = setup_irq(irq, &p->irqaction);
if (ret < 0) {
dev_err(&p->pdev->dev,
"failed to request irq %d\n", irq);
return ret;
}
clockevents_register_device(&p->ced);
platform_set_drvdata(pdev, p);
return 0;
}
static int timer8_probe(struct platform_device *pdev)
{
struct timer8_priv *p = platform_get_drvdata(pdev);
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
return timer8_setup(p, pdev);
}
static int timer8_remove(struct platform_device *pdev)
{
return -EBUSY;
}
static const struct of_device_id timer8_of_table[] __maybe_unused = {
{ .compatible = "renesas,8bit-timer" },
{ }
};
MODULE_DEVICE_TABLE(of, timer8_of_table);
static struct platform_driver timer8_driver = {
.probe = timer8_probe,
.remove = timer8_remove,
.driver = {
.name = "h8300-8timer",
.of_match_table = of_match_ptr(timer8_of_table),
}
};
static int __init timer8_init(void)
{
return platform_driver_register(&timer8_driver);
}
static void __exit timer8_exit(void)
{
platform_driver_unregister(&timer8_driver);
}
subsys_initcall(timer8_init);
module_exit(timer8_exit);
MODULE_AUTHOR("Yoshinori Sato");
MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
MODULE_LICENSE("GPL v2");
/*
* H8/300 TPU Driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
*
*/
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/clocksource.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
#include <asm/irq.h>
#define TCR 0
#define TMDR 1
#define TIOR 2
#define TER 4
#define TSR 5
#define TCNT 6
#define TGRA 8
#define TGRB 10
#define TGRC 12
#define TGRD 14
struct tpu_priv {
struct platform_device *pdev;
struct clocksource cs;
struct clk *clk;
unsigned long mapbase1;
unsigned long mapbase2;
raw_spinlock_t lock;
unsigned int cs_enabled;
};
static inline unsigned long read_tcnt32(struct tpu_priv *p)
{
unsigned long tcnt;
tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16;
tcnt |= ctrl_inw(p->mapbase2 + TCNT);
return tcnt;
}
static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
{
unsigned long v1, v2, v3;
int o1, o2;
o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
o2 = o1;
v1 = read_tcnt32(p);
v2 = read_tcnt32(p);
v3 = read_tcnt32(p);
o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
*val = v2;
return o1;
}
static inline struct tpu_priv *cs_to_priv(struct clocksource *cs)
{
return container_of(cs, struct tpu_priv, cs);
}
static cycle_t tpu_clocksource_read(struct clocksource *cs)
{
struct tpu_priv *p = cs_to_priv(cs);
unsigned long flags;
unsigned long long value;
raw_spin_lock_irqsave(&p->lock, flags);
if (tpu_get_counter(p, &value))
value += 0x100000000;
raw_spin_unlock_irqrestore(&p->lock, flags);
return value;
}
static int tpu_clocksource_enable(struct clocksource *cs)
{
struct tpu_priv *p = cs_to_priv(cs);
WARN_ON(p->cs_enabled);
ctrl_outw(0, p->mapbase1 + TCNT);
ctrl_outw(0, p->mapbase2 + TCNT);
ctrl_outb(0x0f, p->mapbase1 + TCR);
ctrl_outb(0x03, p->mapbase2 + TCR);
p->cs_enabled = true;
return 0;
}
static void tpu_clocksource_disable(struct clocksource *cs)
{
struct tpu_priv *p = cs_to_priv(cs);
WARN_ON(!p->cs_enabled);
ctrl_outb(0, p->mapbase1 + TCR);
ctrl_outb(0, p->mapbase2 + TCR);
p->cs_enabled = false;
}
#define CH_L 0
#define CH_H 1
static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
{
struct resource *res[2];
memset(p, 0, sizeof(*p));
p->pdev = pdev;
res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
if (!res[CH_L] || !res[CH_H]) {
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
return -ENXIO;
}
p->clk = clk_get(&p->pdev->dev, "fck");
if (IS_ERR(p->clk)) {
dev_err(&p->pdev->dev, "can't get clk\n");
return PTR_ERR(p->clk);
}
p->mapbase1 = res[CH_L]->start;
p->mapbase2 = res[CH_H]->start;
p->cs.name = pdev->name;
p->cs.rating = 200;
p->cs.read = tpu_clocksource_read;
p->cs.enable = tpu_clocksource_enable;
p->cs.disable = tpu_clocksource_disable;
p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64);
platform_set_drvdata(pdev, p);
return 0;
}
static int tpu_probe(struct platform_device *pdev)
{
struct tpu_priv *p = platform_get_drvdata(pdev);
if (p) {
dev_info(&pdev->dev, "kept as earlytimer\n");
return 0;
}
p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
return tpu_setup(p, pdev);
}
static int tpu_remove(struct platform_device *pdev)
{
return -EBUSY;
}
static const struct of_device_id tpu_of_table[] = {
{ .compatible = "renesas,tpu" },
{ }
};
static struct platform_driver tpu_driver = {
.probe = tpu_probe,
.remove = tpu_remove,
.driver = {
.name = "h8s-tpu",
.of_match_table = of_match_ptr(tpu_of_table),
}
};
static int __init tpu_init(void)
{
return platform_driver_register(&tpu_driver);
}
static void __exit tpu_exit(void)
{
platform_driver_unregister(&tpu_driver);
}
subsys_initcall(tpu_init);
module_exit(tpu_exit);
MODULE_AUTHOR("Yoshinori Sato");
MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver");
MODULE_LICENSE("GPL v2");
...@@ -159,3 +159,11 @@ config KEYSTONE_IRQ ...@@ -159,3 +159,11 @@ config KEYSTONE_IRQ
config MIPS_GIC config MIPS_GIC
bool bool
select MIPS_CM select MIPS_CM
config RENESAS_H8300H_INTC
bool
select IRQ_DOMAIN
config RENESAS_H8S_INTC
bool
select IRQ_DOMAIN
\ No newline at end of file
...@@ -47,3 +47,5 @@ obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o ...@@ -47,3 +47,5 @@ obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o
obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o
obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o
obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o
obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o
/*
* H8/300H interrupt controller driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/io.h>
#include "irqchip.h"
static const char ipr_bit[] = {
7, 6, 5, 5,
4, 4, 4, 4, 3, 3, 3, 3,
2, 2, 2, 2, 1, 1, 1, 1,
0, 0, 0, 0, 15, 15, 15, 15,
14, 14, 14, 14, 13, 13, 13, 13,
-1, -1, -1, -1, 11, 11, 11, 11,
10, 10, 10, 10, 9, 9, 9, 9,
};
static void *intc_baseaddr;
#define IPR ((unsigned long)intc_baseaddr + 6)
static void h8300h_disable_irq(struct irq_data *data)
{
int bit;
int irq = data->irq - 12;
bit = ipr_bit[irq];
if (bit >= 0) {
if (bit < 8)
ctrl_bclr(bit & 7, IPR);
else
ctrl_bclr(bit & 7, (IPR+1));
}
}
static void h8300h_enable_irq(struct irq_data *data)
{
int bit;
int irq = data->irq - 12;
bit = ipr_bit[irq];
if (bit >= 0) {
if (bit < 8)
ctrl_bset(bit & 7, IPR);
else
ctrl_bset(bit & 7, (IPR+1));
}
}
struct irq_chip h8300h_irq_chip = {
.name = "H8/300H-INTC",
.irq_enable = h8300h_enable_irq,
.irq_disable = h8300h_disable_irq,
};
static int irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw_irq_num)
{
irq_set_chip_and_handler(virq, &h8300h_irq_chip, handle_simple_irq);
return 0;
}
static struct irq_domain_ops irq_ops = {
.map = irq_map,
.xlate = irq_domain_xlate_onecell,
};
static int __init h8300h_intc_of_init(struct device_node *intc,
struct device_node *parent)
{
struct irq_domain *domain;
intc_baseaddr = of_iomap(intc, 0);
BUG_ON(!intc_baseaddr);
/* All interrupt priority low */
ctrl_outb(0x00, IPR + 0);
ctrl_outb(0x00, IPR + 1);
domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL);
BUG_ON(!domain);
irq_set_default_host(domain);
return 0;
}
IRQCHIP_DECLARE(h8300h_intc, "renesas,h8300h-intc", h8300h_intc_of_init);
/*
* H8S interrupt contoller driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourceforge.jp>
*/
#include <linux/irq.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/io.h>
#include "irqchip.h"
static void *intc_baseaddr;
#define IPRA ((unsigned long)intc_baseaddr)
static const unsigned char ipr_table[] = {
0x03, 0x02, 0x01, 0x00, 0x13, 0x12, 0x11, 0x10, /* 16 - 23 */
0x23, 0x22, 0x21, 0x20, 0x33, 0x32, 0x31, 0x30, /* 24 - 31 */
0x43, 0x42, 0x41, 0x40, 0x53, 0x53, 0x52, 0x52, /* 32 - 39 */
0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, /* 40 - 47 */
0x50, 0x50, 0x50, 0x50, 0x63, 0x63, 0x63, 0x63, /* 48 - 55 */
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, /* 56 - 63 */
0x61, 0x61, 0x61, 0x61, 0x60, 0x60, 0x60, 0x60, /* 64 - 71 */
0x73, 0x73, 0x73, 0x73, 0x72, 0x72, 0x72, 0x72, /* 72 - 79 */
0x71, 0x71, 0x71, 0x71, 0x70, 0x83, 0x82, 0x81, /* 80 - 87 */
0x80, 0x80, 0x80, 0x80, 0x93, 0x93, 0x93, 0x93, /* 88 - 95 */
0x92, 0x92, 0x92, 0x92, 0x91, 0x91, 0x91, 0x91, /* 96 - 103 */
0x90, 0x90, 0x90, 0x90, 0xa3, 0xa3, 0xa3, 0xa3, /* 104 - 111 */
0xa2, 0xa2, 0xa2, 0xa2, 0xa1, 0xa1, 0xa1, 0xa1, /* 112 - 119 */
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, /* 120 - 127 */
};
static void h8s_disable_irq(struct irq_data *data)
{
int pos;
unsigned int addr;
unsigned short pri;
int irq = data->irq;
addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3);
pos = (ipr_table[irq - 16] & 0x0f) * 4;
pri = ~(0x000f << pos);
pri &= ctrl_inw(addr);
ctrl_outw(pri, addr);
}
static void h8s_enable_irq(struct irq_data *data)
{
int pos;
unsigned int addr;
unsigned short pri;
int irq = data->irq;
addr = IPRA + ((ipr_table[irq - 16] & 0xf0) >> 3);
pos = (ipr_table[irq - 16] & 0x0f) * 4;
pri = ~(0x000f << pos);
pri &= ctrl_inw(addr);
pri |= 1 << pos;
ctrl_outw(pri, addr);
}
struct irq_chip h8s_irq_chip = {
.name = "H8S-INTC",
.irq_enable = h8s_enable_irq,
.irq_disable = h8s_disable_irq,
};
static __init int irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw_irq_num)
{
irq_set_chip_and_handler(virq, &h8s_irq_chip, handle_simple_irq);
return 0;
}
static struct irq_domain_ops irq_ops = {
.map = irq_map,
.xlate = irq_domain_xlate_onecell,
};
static int __init h8s_intc_of_init(struct device_node *intc,
struct device_node *parent)
{
struct irq_domain *domain;
int n;
intc_baseaddr = of_iomap(intc, 0);
BUG_ON(!intc_baseaddr);
/* All interrupt priority is 0 (disable) */
/* IPRA to IPRK */
for (n = 0; n <= 'k' - 'a'; n++)
ctrl_outw(0x0000, IPRA + (n * 2));
domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL);
BUG_ON(!domain);
irq_set_default_host(domain);
return 0;
}
IRQCHIP_DECLARE(h8s_intc, "renesas,h8s-intc", h8s_intc_of_init);
...@@ -728,7 +728,7 @@ config SERIAL_IP22_ZILOG_CONSOLE ...@@ -728,7 +728,7 @@ config SERIAL_IP22_ZILOG_CONSOLE
config SERIAL_SH_SCI config SERIAL_SH_SCI
tristate "SuperH SCI(F) serial port support" tristate "SuperH SCI(F) serial port support"
depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST depends on SUPERH || ARCH_SHMOBILE || H8300 || COMPILE_TEST
select SERIAL_CORE select SERIAL_CORE
config SERIAL_SH_SCI_NR_UARTS config SERIAL_SH_SCI_NR_UARTS
......
...@@ -84,7 +84,7 @@ struct sci_port { ...@@ -84,7 +84,7 @@ struct sci_port {
int overrun_bit; int overrun_bit;
unsigned int error_mask; unsigned int error_mask;
unsigned int sampling_rate; unsigned int sampling_rate;
resource_size_t reg_size;
/* Break timer */ /* Break timer */
struct timer_list break_timer; struct timer_list break_timer;
...@@ -2073,23 +2073,9 @@ static const char *sci_type(struct uart_port *port) ...@@ -2073,23 +2073,9 @@ static const char *sci_type(struct uart_port *port)
return NULL; return NULL;
} }
static inline unsigned long sci_port_size(struct uart_port *port)
{
/*
* Pick an arbitrary size that encapsulates all of the base
* registers by default. This can be optimized later, or derived
* from platform resource data at such a time that ports begin to
* behave more erratically.
*/
if (port->type == PORT_HSCIF)
return 96;
else
return 64;
}
static int sci_remap_port(struct uart_port *port) static int sci_remap_port(struct uart_port *port)
{ {
unsigned long size = sci_port_size(port); struct sci_port *sport = to_sci_port(port);
/* /*
* Nothing to do if there's already an established membase. * Nothing to do if there's already an established membase.
...@@ -2098,7 +2084,7 @@ static int sci_remap_port(struct uart_port *port) ...@@ -2098,7 +2084,7 @@ static int sci_remap_port(struct uart_port *port)
return 0; return 0;
if (port->flags & UPF_IOREMAP) { if (port->flags & UPF_IOREMAP) {
port->membase = ioremap_nocache(port->mapbase, size); port->membase = ioremap_nocache(port->mapbase, sport->reg_size);
if (unlikely(!port->membase)) { if (unlikely(!port->membase)) {
dev_err(port->dev, "can't remap port#%d\n", port->line); dev_err(port->dev, "can't remap port#%d\n", port->line);
return -ENXIO; return -ENXIO;
...@@ -2117,23 +2103,28 @@ static int sci_remap_port(struct uart_port *port) ...@@ -2117,23 +2103,28 @@ static int sci_remap_port(struct uart_port *port)
static void sci_release_port(struct uart_port *port) static void sci_release_port(struct uart_port *port)
{ {
struct sci_port *sport = to_sci_port(port);
if (port->flags & UPF_IOREMAP) { if (port->flags & UPF_IOREMAP) {
iounmap(port->membase); iounmap(port->membase);
port->membase = NULL; port->membase = NULL;
} }
release_mem_region(port->mapbase, sci_port_size(port)); release_mem_region(port->mapbase, sport->reg_size);
} }
static int sci_request_port(struct uart_port *port) static int sci_request_port(struct uart_port *port)
{ {
unsigned long size = sci_port_size(port);
struct resource *res; struct resource *res;
struct sci_port *sport = to_sci_port(port);
int ret; int ret;
res = request_mem_region(port->mapbase, size, dev_name(port->dev)); res = request_mem_region(port->mapbase, sport->reg_size,
if (unlikely(res == NULL)) dev_name(port->dev));
if (unlikely(res == NULL)) {
dev_err(port->dev, "request_mem_region failed.");
return -EBUSY; return -EBUSY;
}
ret = sci_remap_port(port); ret = sci_remap_port(port);
if (unlikely(ret != 0)) { if (unlikely(ret != 0)) {
...@@ -2207,6 +2198,7 @@ static int sci_init_single(struct platform_device *dev, ...@@ -2207,6 +2198,7 @@ static int sci_init_single(struct platform_device *dev,
return -ENOMEM; return -ENOMEM;
port->mapbase = res->start; port->mapbase = res->start;
sci_port->reg_size = resource_size(res);
for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i) for (i = 0; i < ARRAY_SIZE(sci_port->irqs); ++i)
sci_port->irqs[i] = platform_get_irq(dev, i); sci_port->irqs[i] = platform_get_irq(dev, i);
...@@ -2535,6 +2527,12 @@ static const struct of_device_id of_sci_match[] = { ...@@ -2535,6 +2527,12 @@ static const struct of_device_id of_sci_match[] = {
.type = PORT_HSCIF, .type = PORT_HSCIF,
.regtype = SCIx_HSCIF_REGTYPE, .regtype = SCIx_HSCIF_REGTYPE,
}, },
}, {
.compatible = "renesas,sci",
.data = &(const struct sci_port_info) {
.type = PORT_SCI,
.regtype = SCIx_SCI_REGTYPE,
},
}, { }, {
/* Terminator */ /* Terminator */
}, },
......
#include <generated/asm-offsets.h>
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#define EM_ARM 40 /* ARM 32 bit */ #define EM_ARM 40 /* ARM 32 bit */
#define EM_SH 42 /* SuperH */ #define EM_SH 42 /* SuperH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */ #define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_H8_300 46 /* Renesas H8/300 */
#define EM_IA_64 50 /* HP/Intel IA-64 */ #define EM_IA_64 50 /* HP/Intel IA-64 */
#define EM_X86_64 62 /* AMD x86-64 */ #define EM_X86_64 62 /* AMD x86-64 */
#define EM_S390 22 /* IBM S/390 */ #define EM_S390 22 /* IBM S/390 */
......
...@@ -41,4 +41,4 @@ ...@@ -41,4 +41,4 @@
# so we just ignore them to let readprofile continue to work. # so we just ignore them to let readprofile continue to work.
# (At least sparc64 has __crc_ in the middle). # (At least sparc64 has __crc_ in the middle).
$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)' > $2 $NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( .L\)' > $2
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