Commit 5872c840 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'microblaze-3.12-rc1' of git://git.monstr.eu/linux-2.6-microblaze

Pull Microblaze patches from Michal Simek:
 - PCI fixes
 - Selfmod code removing
 - Intc and timer fixes
 - Adding new MB versions
 - Minor fixes

* tag 'microblaze-3.12-rc1' of git://git.monstr.eu/linux-2.6-microblaze:
  microblaze: Show message when reset gpio is not present
  microblaze: Add linux.bin.ub target
  microblaze: Add PVR version string for MB v9.0 and v9.1
  microblaze: timer: Replace microblaze_ prefix by xilinx_
  microblaze: timer: Update header
  microblaze: timer: Remove unused header
  microblaze: timer: Clear driver init function
  microblaze: timer: Use CLKSRC_OF initialization
  microblaze: intc: Remove unused header
  microblaze: intc: Clean driver init function
  microblaze: intc: Using irqchip
  microblaze: intc: Update header
  microblaze: intc: Remove unused headers
  microblaze: Remove selfmodified feature
  of/pci: Use of_pci_range_parser
parents 39eda2ab 54ea21f0
...@@ -29,6 +29,7 @@ config MICROBLAZE ...@@ -29,6 +29,7 @@ config MICROBLAZE
select GENERIC_IDLE_POLL_SETUP select GENERIC_IDLE_POLL_SETUP
select MODULES_USE_ELF_RELA select MODULES_USE_ELF_RELA
select CLONE_BACKWARDS3 select CLONE_BACKWARDS3
select CLKSRC_OF
config SWAP config SWAP
def_bool n def_bool n
......
...@@ -72,7 +72,7 @@ all: linux.bin ...@@ -72,7 +72,7 @@ all: linux.bin
archclean: archclean:
$(Q)$(MAKE) $(clean)=$(boot) $(Q)$(MAKE) $(clean)=$(boot)
linux.bin linux.bin.gz: vmlinux linux.bin linux.bin.gz linux.bin.ub: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
simpleImage.%: vmlinux simpleImage.%: vmlinux
...@@ -81,6 +81,7 @@ simpleImage.%: vmlinux ...@@ -81,6 +81,7 @@ simpleImage.%: vmlinux
define archhelp define archhelp
echo '* linux.bin - Create raw binary' echo '* linux.bin - Create raw binary'
echo ' linux.bin.gz - Create compressed raw binary' echo ' linux.bin.gz - Create compressed raw binary'
echo ' linux.bin.ub - Create U-Boot wrapped raw binary'
echo ' simpleImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in' echo ' simpleImage.<dt> - ELF image with $(arch)/boot/dts/<dt>.dts linked in'
echo ' - stripped elf with fdt blob' echo ' - stripped elf with fdt blob'
echo ' simpleImage.<dt>.unstrip - full ELF image with fdt blob' echo ' simpleImage.<dt>.unstrip - full ELF image with fdt blob'
......
...@@ -2,12 +2,15 @@ ...@@ -2,12 +2,15 @@
# arch/microblaze/boot/Makefile # arch/microblaze/boot/Makefile
# #
targets := linux.bin linux.bin.gz simpleImage.% targets := linux.bin linux.bin.gz linux.bin.ub simpleImage.%
OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary OBJCOPYFLAGS := -R .note -R .comment -R .note.gnu.build-id -O binary
$(obj)/linux.bin: vmlinux FORCE $(obj)/linux.bin: vmlinux FORCE
$(call if_changed,objcopy) $(call if_changed,objcopy)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
$(obj)/linux.bin.ub: $(obj)/linux.bin FORCE
$(call if_changed,uimage) $(call if_changed,uimage)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')' @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
...@@ -22,8 +25,6 @@ quiet_cmd_strip = STRIP $@ ...@@ -22,8 +25,6 @@ quiet_cmd_strip = STRIP $@
cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \ cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
-K _fdt_start vmlinux -o $@ -K _fdt_start vmlinux -o $@
UIMAGE_IN = $@
UIMAGE_OUT = $@.ub
UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR) UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
$(obj)/simpleImage.%: vmlinux FORCE $(obj)/simpleImage.%: vmlinux FORCE
......
/*
* Copyright (C) 2007-2008 Michal Simek <monstr@monstr.eu>
*
* 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 _ASM_MICROBLAZE_SELFMOD_H
#define _ASM_MICROBLAZE_SELFMOD_H
/*
* BARRIER_BASE_ADDR is constant address for selfmod function.
* do not change this value - selfmod function is in
* arch/microblaze/kernel/selfmod.c: selfmod_function()
*
* last 16 bits is used for storing register offset
*/
#define BARRIER_BASE_ADDR 0x1234ff00
void selfmod_function(const int *arr_fce, const unsigned int base);
#endif /* _ASM_MICROBLAZE_SELFMOD_H */
...@@ -7,7 +7,6 @@ ifdef CONFIG_FUNCTION_TRACER ...@@ -7,7 +7,6 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_timer.o = -pg CFLAGS_REMOVE_timer.o = -pg
CFLAGS_REMOVE_intc.o = -pg CFLAGS_REMOVE_intc.o = -pg
CFLAGS_REMOVE_early_printk.o = -pg CFLAGS_REMOVE_early_printk.o = -pg
CFLAGS_REMOVE_selfmod.o = -pg
CFLAGS_REMOVE_heartbeat.o = -pg CFLAGS_REMOVE_heartbeat.o = -pg
CFLAGS_REMOVE_ftrace.o = -pg CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_process.o = -pg CFLAGS_REMOVE_process.o = -pg
...@@ -23,7 +22,6 @@ obj-y += dma.o exceptions.o \ ...@@ -23,7 +22,6 @@ obj-y += dma.o exceptions.o \
obj-y += cpu/ obj-y += cpu/
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SELFMOD) += selfmod.o
obj-$(CONFIG_HEART_BEAT) += heartbeat.o obj-$(CONFIG_HEART_BEAT) += heartbeat.o
obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU) += misc.o obj-$(CONFIG_MMU) += misc.o
......
...@@ -39,6 +39,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = { ...@@ -39,6 +39,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"8.30.a", 0x17}, {"8.30.a", 0x17},
{"8.40.a", 0x18}, {"8.40.a", 0x18},
{"8.40.b", 0x19}, {"8.40.b", 0x19},
{"9.0", 0x1b},
{"9.1", 0x1d},
{NULL, 0}, {NULL, 0},
}; };
......
/* /*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2012-2013 Xilinx, Inc.
* Copyright (C) 2007-2009 PetaLogix * Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, Inc. * Copyright (C) 2006 Atmark Techno, Inc.
* *
...@@ -8,23 +9,15 @@ ...@@ -8,23 +9,15 @@
* for more details. * for more details.
*/ */
#include <linux/init.h>
#include <linux/irqdomain.h> #include <linux/irqdomain.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <asm/page.h> #include <linux/of_address.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <asm/prom.h> #include "../../drivers/irqchip/irqchip.h"
#include <asm/irq.h>
#ifdef CONFIG_SELFMOD_INTC static void __iomem *intc_baseaddr;
#include <asm/selfmod.h>
#define INTC_BASE BARRIER_BASE_ADDR
#else
static unsigned int intc_baseaddr;
#define INTC_BASE intc_baseaddr
#endif
/* No one else should require these constants, so define them locally here. */ /* No one else should require these constants, so define them locally here. */
#define ISR 0x00 /* Interrupt Status Register */ #define ISR 0x00 /* Interrupt Status Register */
...@@ -50,21 +43,21 @@ static void intc_enable_or_unmask(struct irq_data *d) ...@@ -50,21 +43,21 @@ static void intc_enable_or_unmask(struct irq_data *d)
* acks the irq before calling the interrupt handler * acks the irq before calling the interrupt handler
*/ */
if (irqd_is_level_type(d)) if (irqd_is_level_type(d))
out_be32(INTC_BASE + IAR, mask); out_be32(intc_baseaddr + IAR, mask);
out_be32(INTC_BASE + SIE, mask); out_be32(intc_baseaddr + SIE, mask);
} }
static void intc_disable_or_mask(struct irq_data *d) static void intc_disable_or_mask(struct irq_data *d)
{ {
pr_debug("disable: %ld\n", d->hwirq); pr_debug("disable: %ld\n", d->hwirq);
out_be32(INTC_BASE + CIE, 1 << d->hwirq); out_be32(intc_baseaddr + CIE, 1 << d->hwirq);
} }
static void intc_ack(struct irq_data *d) static void intc_ack(struct irq_data *d)
{ {
pr_debug("ack: %ld\n", d->hwirq); pr_debug("ack: %ld\n", d->hwirq);
out_be32(INTC_BASE + IAR, 1 << d->hwirq); out_be32(intc_baseaddr + IAR, 1 << d->hwirq);
} }
static void intc_mask_ack(struct irq_data *d) static void intc_mask_ack(struct irq_data *d)
...@@ -72,8 +65,8 @@ static void intc_mask_ack(struct irq_data *d) ...@@ -72,8 +65,8 @@ static void intc_mask_ack(struct irq_data *d)
unsigned long mask = 1 << d->hwirq; unsigned long mask = 1 << d->hwirq;
pr_debug("disable_and_ack: %ld\n", d->hwirq); pr_debug("disable_and_ack: %ld\n", d->hwirq);
out_be32(INTC_BASE + CIE, mask); out_be32(intc_baseaddr + CIE, mask);
out_be32(INTC_BASE + IAR, mask); out_be32(intc_baseaddr + IAR, mask);
} }
static struct irq_chip intc_dev = { static struct irq_chip intc_dev = {
...@@ -90,7 +83,7 @@ unsigned int get_irq(void) ...@@ -90,7 +83,7 @@ unsigned int get_irq(void)
{ {
unsigned int hwirq, irq = -1; unsigned int hwirq, irq = -1;
hwirq = in_be32(INTC_BASE + IVR); hwirq = in_be32(intc_baseaddr + IVR);
if (hwirq != -1U) if (hwirq != -1U)
irq = irq_find_mapping(root_domain, hwirq); irq = irq_find_mapping(root_domain, hwirq);
...@@ -120,40 +113,32 @@ static const struct irq_domain_ops xintc_irq_domain_ops = { ...@@ -120,40 +113,32 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {
.map = xintc_map, .map = xintc_map,
}; };
void __init init_IRQ(void) static int __init xilinx_intc_of_init(struct device_node *intc,
struct device_node *parent)
{ {
u32 nr_irq, intr_mask; u32 nr_irq, intr_mask;
struct device_node *intc = NULL; int ret;
#ifdef CONFIG_SELFMOD_INTC
unsigned int intc_baseaddr = 0; intc_baseaddr = of_iomap(intc, 0);
static int arr_func[] = { BUG_ON(!intc_baseaddr);
(int)&get_irq,
(int)&intc_enable_or_unmask, ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
(int)&intc_disable_or_mask, if (ret < 0) {
(int)&intc_mask_ack, pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__);
(int)&intc_ack, return -EINVAL;
(int)&intc_end, }
0
}; ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask);
#endif if (ret < 0) {
intc = of_find_compatible_node(NULL, NULL, "xlnx,xps-intc-1.00.a"); pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
BUG_ON(!intc); return -EINVAL;
}
intc_baseaddr = be32_to_cpup(of_get_property(intc, "reg", NULL));
intc_baseaddr = (unsigned long) ioremap(intc_baseaddr, PAGE_SIZE);
nr_irq = be32_to_cpup(of_get_property(intc,
"xlnx,num-intr-inputs", NULL));
intr_mask =
be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL));
if (intr_mask > (u32)((1ULL << nr_irq) - 1)) if (intr_mask > (u32)((1ULL << nr_irq) - 1))
pr_info(" ERROR: Mismatch in kind-of-intr param\n"); pr_info(" ERROR: Mismatch in kind-of-intr param\n");
#ifdef CONFIG_SELFMOD_INTC pr_info("%s: num_irq=%d, edge=0x%x\n",
selfmod_function((int *) arr_func, intc_baseaddr); intc->full_name, nr_irq, intr_mask);
#endif
pr_info("%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
intc->name, intc_baseaddr, nr_irq, intr_mask);
/* /*
* Disable all external interrupts until they are * Disable all external interrupts until they are
...@@ -174,4 +159,8 @@ void __init init_IRQ(void) ...@@ -174,4 +159,8 @@ void __init init_IRQ(void)
(void *)intr_mask); (void *)intr_mask);
irq_set_default_host(root_domain); irq_set_default_host(root_domain);
return 0;
} }
IRQCHIP_DECLARE(xilinx_intc, "xlnx,xps-intc-1.00.a", xilinx_intc_of_init);
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/irqchip.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/export.h>
#include <asm/prom.h>
static u32 concurrent_irq; static u32 concurrent_irq;
...@@ -47,3 +45,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs) ...@@ -47,3 +45,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
set_irq_regs(old_regs); set_irq_regs(old_regs);
trace_hardirqs_on(); trace_hardirqs_on();
} }
void __init init_IRQ(void)
{
/* process the entire interrupt tree in one go */
irqchip_init();
}
...@@ -67,7 +67,11 @@ static void gpio_system_reset(void) ...@@ -67,7 +67,11 @@ static void gpio_system_reset(void)
pr_notice("Reset GPIO unavailable - halting!\n"); pr_notice("Reset GPIO unavailable - halting!\n");
} }
#else #else
#define gpio_system_reset() do {} while (0) static void gpio_system_reset(void)
{
pr_notice("No reset GPIO present - halting!\n");
}
void of_platform_reset_gpio_probe(void) void of_platform_reset_gpio_probe(void)
{ {
return; return;
......
/*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2009 PetaLogix
*
* 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/interrupt.h>
#include <asm/selfmod.h>
#undef DEBUG
#if __GNUC__ > 3
#error GCC 4 unsupported SELFMOD. Please disable SELFMOD from menuconfig.
#endif
#define OPCODE_IMM 0xB0000000
#define OPCODE_LWI 0xE8000000
#define OPCODE_LWI_MASK 0xEC000000
#define OPCODE_RTSD 0xB60F0008 /* return from func: rtsd r15, 8 */
#define OPCODE_ADDIK 0x30000000
#define OPCODE_ADDIK_MASK 0xFC000000
#define IMM_BASE (OPCODE_IMM | (BARRIER_BASE_ADDR >> 16))
#define LWI_BASE (OPCODE_LWI | (BARRIER_BASE_ADDR & 0x0000ff00))
#define LWI_BASE_MASK (OPCODE_LWI_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define ADDIK_BASE (OPCODE_ADDIK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define ADDIK_BASE_MASK (OPCODE_ADDIK_MASK | (BARRIER_BASE_ADDR & 0x0000ff00))
#define MODIFY_INSTR { \
pr_debug("%s: curr instr, (%d):0x%x, next(%d):0x%x\n", \
__func__, i, addr[i], i + 1, addr[i + 1]); \
addr[i] = OPCODE_IMM + (base >> 16); \
/* keep instruction opcode and add only last 16bits */ \
addr[i + 1] = (addr[i + 1] & 0xffff00ff) + (base & 0xffff); \
__invalidate_icache(addr[i]); \
__invalidate_icache(addr[i + 1]); \
pr_debug("%s: hack instr, (%d):0x%x, next(%d):0x%x\n", \
__func__, i, addr[i], i + 1, addr[i + 1]); }
/* NOTE
* self-modified part of code for improvement of interrupt controller
* save instruction in interrupt rutine
*/
void selfmod_function(const int *arr_fce, const unsigned int base)
{
unsigned int flags, i, j, *addr = NULL;
local_irq_save(flags);
__disable_icache();
/* zero terminated array */
for (j = 0; arr_fce[j] != 0; j++) {
/* get start address of function */
addr = (unsigned int *) arr_fce[j];
pr_debug("%s: func(%d) at 0x%x\n",
__func__, j, (unsigned int) addr);
for (i = 0; ; i++) {
pr_debug("%s: instruction code at %d: 0x%x\n",
__func__, i, addr[i]);
if (addr[i] == IMM_BASE) {
/* detecting of lwi (0xE8) or swi (0xF8) instr
* I can detect both opcode with one mask */
if ((addr[i + 1] & LWI_BASE_MASK) == LWI_BASE) {
MODIFY_INSTR;
} else /* detection addik for ack */
if ((addr[i + 1] & ADDIK_BASE_MASK) ==
ADDIK_BASE) {
MODIFY_INSTR;
}
} else if (addr[i] == OPCODE_RTSD) {
/* return from function means end of function */
pr_debug("%s: end of array %d\n", __func__, i);
break;
}
}
}
local_irq_restore(flags);
} /* end of self-modified code */
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/clocksource.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/cpu.h> #include <linux/cpu.h>
...@@ -68,10 +69,6 @@ void __init setup_arch(char **cmdline_p) ...@@ -68,10 +69,6 @@ void __init setup_arch(char **cmdline_p)
xilinx_pci_init(); xilinx_pci_init();
#if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
pr_notice("Self modified code enable\n");
#endif
#ifdef CONFIG_VT #ifdef CONFIG_VT
#if defined(CONFIG_XILINX_CONSOLE) #if defined(CONFIG_XILINX_CONSOLE)
conswitchp = &xil_con; conswitchp = &xil_con;
...@@ -196,6 +193,11 @@ void __init machine_early_init(const char *cmdline, unsigned int ram, ...@@ -196,6 +193,11 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
per_cpu(CURRENT_SAVE, 0) = (unsigned long)current; per_cpu(CURRENT_SAVE, 0) = (unsigned long)current;
} }
void __init time_init(void)
{
clocksource_of_init();
}
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *of_debugfs_root; struct dentry *of_debugfs_root;
......
/* /*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu> * Copyright (C) 2007-2013 Michal Simek <monstr@monstr.eu>
* Copyright (C) 2012-2013 Xilinx, Inc.
* Copyright (C) 2007-2009 PetaLogix * Copyright (C) 2007-2009 PetaLogix
* Copyright (C) 2006 Atmark Techno, Inc. * Copyright (C) 2006 Atmark Techno, Inc.
* *
...@@ -8,34 +9,16 @@ ...@@ -8,34 +9,16 @@
* for more details. * for more details.
*/ */
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/param.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/profile.h>
#include <linux/irq.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/err.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/io.h> #include <linux/of_address.h>
#include <linux/bug.h>
#include <asm/cpuinfo.h> #include <asm/cpuinfo.h>
#include <asm/setup.h>
#include <asm/prom.h>
#include <asm/irq.h>
#include <linux/cnt32_to_63.h> #include <linux/cnt32_to_63.h>
#ifdef CONFIG_SELFMOD_TIMER static void __iomem *timer_baseaddr;
#include <asm/selfmod.h>
#define TIMER_BASE BARRIER_BASE_ADDR
#else
static unsigned int timer_baseaddr;
#define TIMER_BASE timer_baseaddr
#endif
static unsigned int freq_div_hz; static unsigned int freq_div_hz;
static unsigned int timer_clock_freq; static unsigned int timer_clock_freq;
...@@ -59,19 +42,21 @@ static unsigned int timer_clock_freq; ...@@ -59,19 +42,21 @@ static unsigned int timer_clock_freq;
#define TCSR_PWMA (1<<9) #define TCSR_PWMA (1<<9)
#define TCSR_ENALL (1<<10) #define TCSR_ENALL (1<<10)
static inline void microblaze_timer0_stop(void) static inline void xilinx_timer0_stop(void)
{ {
out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0) & ~TCSR_ENT); out_be32(timer_baseaddr + TCSR0,
in_be32(timer_baseaddr + TCSR0) & ~TCSR_ENT);
} }
static inline void microblaze_timer0_start_periodic(unsigned long load_val) static inline void xilinx_timer0_start_periodic(unsigned long load_val)
{ {
if (!load_val) if (!load_val)
load_val = 1; load_val = 1;
out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ /* loading value to timer reg */
out_be32(timer_baseaddr + TLR0, load_val);
/* load the initial value */ /* load the initial value */
out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); out_be32(timer_baseaddr + TCSR0, TCSR_LOAD);
/* see timer data sheet for detail /* see timer data sheet for detail
* !ENALL - don't enable 'em all * !ENALL - don't enable 'em all
...@@ -86,38 +71,39 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val) ...@@ -86,38 +71,39 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)
* UDT - set the timer as down counter * UDT - set the timer as down counter
* !MDT0 - generate mode * !MDT0 - generate mode
*/ */
out_be32(TIMER_BASE + TCSR0, out_be32(timer_baseaddr + TCSR0,
TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
} }
static inline void microblaze_timer0_start_oneshot(unsigned long load_val) static inline void xilinx_timer0_start_oneshot(unsigned long load_val)
{ {
if (!load_val) if (!load_val)
load_val = 1; load_val = 1;
out_be32(TIMER_BASE + TLR0, load_val); /* loading value to timer reg */ /* loading value to timer reg */
out_be32(timer_baseaddr + TLR0, load_val);
/* load the initial value */ /* load the initial value */
out_be32(TIMER_BASE + TCSR0, TCSR_LOAD); out_be32(timer_baseaddr + TCSR0, TCSR_LOAD);
out_be32(TIMER_BASE + TCSR0, out_be32(timer_baseaddr + TCSR0,
TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT); TCSR_TINT|TCSR_ENIT|TCSR_ENT|TCSR_ARHT|TCSR_UDT);
} }
static int microblaze_timer_set_next_event(unsigned long delta, static int xilinx_timer_set_next_event(unsigned long delta,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
pr_debug("%s: next event, delta %x\n", __func__, (u32)delta); pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
microblaze_timer0_start_oneshot(delta); xilinx_timer0_start_oneshot(delta);
return 0; return 0;
} }
static void microblaze_timer_set_mode(enum clock_event_mode mode, static void xilinx_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
switch (mode) { switch (mode) {
case CLOCK_EVT_MODE_PERIODIC: case CLOCK_EVT_MODE_PERIODIC:
pr_info("%s: periodic\n", __func__); pr_info("%s: periodic\n", __func__);
microblaze_timer0_start_periodic(freq_div_hz); xilinx_timer0_start_periodic(freq_div_hz);
break; break;
case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_ONESHOT:
pr_info("%s: oneshot\n", __func__); pr_info("%s: oneshot\n", __func__);
...@@ -127,7 +113,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, ...@@ -127,7 +113,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
break; break;
case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN:
pr_info("%s: shutdown\n", __func__); pr_info("%s: shutdown\n", __func__);
microblaze_timer0_stop(); xilinx_timer0_stop();
break; break;
case CLOCK_EVT_MODE_RESUME: case CLOCK_EVT_MODE_RESUME:
pr_info("%s: resume\n", __func__); pr_info("%s: resume\n", __func__);
...@@ -135,23 +121,23 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode, ...@@ -135,23 +121,23 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
} }
} }
static struct clock_event_device clockevent_microblaze_timer = { static struct clock_event_device clockevent_xilinx_timer = {
.name = "microblaze_clockevent", .name = "xilinx_clockevent",
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
.shift = 8, .shift = 8,
.rating = 300, .rating = 300,
.set_next_event = microblaze_timer_set_next_event, .set_next_event = xilinx_timer_set_next_event,
.set_mode = microblaze_timer_set_mode, .set_mode = xilinx_timer_set_mode,
}; };
static inline void timer_ack(void) static inline void timer_ack(void)
{ {
out_be32(TIMER_BASE + TCSR0, in_be32(TIMER_BASE + TCSR0)); out_be32(timer_baseaddr + TCSR0, in_be32(timer_baseaddr + TCSR0));
} }
static irqreturn_t timer_interrupt(int irq, void *dev_id) static irqreturn_t timer_interrupt(int irq, void *dev_id)
{ {
struct clock_event_device *evt = &clockevent_microblaze_timer; struct clock_event_device *evt = &clockevent_xilinx_timer;
#ifdef CONFIG_HEART_BEAT #ifdef CONFIG_HEART_BEAT
heartbeat(); heartbeat();
#endif #endif
...@@ -164,73 +150,74 @@ static struct irqaction timer_irqaction = { ...@@ -164,73 +150,74 @@ static struct irqaction timer_irqaction = {
.handler = timer_interrupt, .handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_TIMER, .flags = IRQF_DISABLED | IRQF_TIMER,
.name = "timer", .name = "timer",
.dev_id = &clockevent_microblaze_timer, .dev_id = &clockevent_xilinx_timer,
}; };
static __init void microblaze_clockevent_init(void) static __init void xilinx_clockevent_init(void)
{ {
clockevent_microblaze_timer.mult = clockevent_xilinx_timer.mult =
div_sc(timer_clock_freq, NSEC_PER_SEC, div_sc(timer_clock_freq, NSEC_PER_SEC,
clockevent_microblaze_timer.shift); clockevent_xilinx_timer.shift);
clockevent_microblaze_timer.max_delta_ns = clockevent_xilinx_timer.max_delta_ns =
clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer); clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
clockevent_microblaze_timer.min_delta_ns = clockevent_xilinx_timer.min_delta_ns =
clockevent_delta2ns(1, &clockevent_microblaze_timer); clockevent_delta2ns(1, &clockevent_xilinx_timer);
clockevent_microblaze_timer.cpumask = cpumask_of(0); clockevent_xilinx_timer.cpumask = cpumask_of(0);
clockevents_register_device(&clockevent_microblaze_timer); clockevents_register_device(&clockevent_xilinx_timer);
} }
static cycle_t microblaze_read(struct clocksource *cs) static cycle_t xilinx_read(struct clocksource *cs)
{ {
/* reading actual value of timer 1 */ /* reading actual value of timer 1 */
return (cycle_t) (in_be32(TIMER_BASE + TCR1)); return (cycle_t) (in_be32(timer_baseaddr + TCR1));
} }
static struct timecounter microblaze_tc = { static struct timecounter xilinx_tc = {
.cc = NULL, .cc = NULL,
}; };
static cycle_t microblaze_cc_read(const struct cyclecounter *cc) static cycle_t xilinx_cc_read(const struct cyclecounter *cc)
{ {
return microblaze_read(NULL); return xilinx_read(NULL);
} }
static struct cyclecounter microblaze_cc = { static struct cyclecounter xilinx_cc = {
.read = microblaze_cc_read, .read = xilinx_cc_read,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(32),
.shift = 8, .shift = 8,
}; };
static int __init init_microblaze_timecounter(void) static int __init init_xilinx_timecounter(void)
{ {
microblaze_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC, xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
microblaze_cc.shift); xilinx_cc.shift);
timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock()); timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
return 0; return 0;
} }
static struct clocksource clocksource_microblaze = { static struct clocksource clocksource_microblaze = {
.name = "microblaze_clocksource", .name = "xilinx_clocksource",
.rating = 300, .rating = 300,
.read = microblaze_read, .read = xilinx_read,
.mask = CLOCKSOURCE_MASK(32), .mask = CLOCKSOURCE_MASK(32),
.flags = CLOCK_SOURCE_IS_CONTINUOUS, .flags = CLOCK_SOURCE_IS_CONTINUOUS,
}; };
static int __init microblaze_clocksource_init(void) static int __init xilinx_clocksource_init(void)
{ {
if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq)) if (clocksource_register_hz(&clocksource_microblaze, timer_clock_freq))
panic("failed to register clocksource"); panic("failed to register clocksource");
/* stop timer1 */ /* stop timer1 */
out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT); out_be32(timer_baseaddr + TCSR1,
in_be32(timer_baseaddr + TCSR1) & ~TCSR_ENT);
/* start timer1 - up counting without interrupt */ /* start timer1 - up counting without interrupt */
out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT); out_be32(timer_baseaddr + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
/* register timecounter - for ftrace support */ /* register timecounter - for ftrace support */
init_microblaze_timecounter(); init_xilinx_timecounter();
return 0; return 0;
} }
...@@ -240,55 +227,31 @@ static int __init microblaze_clocksource_init(void) ...@@ -240,55 +227,31 @@ static int __init microblaze_clocksource_init(void)
*/ */
static int timer_initialized; static int timer_initialized;
void __init time_init(void) static void __init xilinx_timer_init(struct device_node *timer)
{ {
u32 irq; u32 irq;
u32 timer_num = 1; u32 timer_num = 1;
struct device_node *timer = NULL; int ret;
const void *prop;
#ifdef CONFIG_SELFMOD_TIMER timer_baseaddr = of_iomap(timer, 0);
unsigned int timer_baseaddr = 0; if (!timer_baseaddr) {
int arr_func[] = { pr_err("ERROR: invalid timer base address\n");
(int)&microblaze_read, BUG();
(int)&timer_interrupt, }
(int)&microblaze_clocksource_init,
(int)&microblaze_timer_set_mode,
(int)&microblaze_timer_set_next_event,
0
};
#endif
prop = of_get_property(of_chosen, "system-timer", NULL);
if (prop)
timer = of_find_node_by_phandle(be32_to_cpup(prop));
else
pr_info("No chosen timer found, using default\n");
if (!timer)
timer = of_find_compatible_node(NULL, NULL,
"xlnx,xps-timer-1.00.a");
BUG_ON(!timer);
timer_baseaddr = be32_to_cpup(of_get_property(timer, "reg", NULL));
timer_baseaddr = (unsigned long) ioremap(timer_baseaddr, PAGE_SIZE);
irq = irq_of_parse_and_map(timer, 0); irq = irq_of_parse_and_map(timer, 0);
timer_num = be32_to_cpup(of_get_property(timer,
"xlnx,one-timer-only", NULL)); of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
if (timer_num) { if (timer_num) {
pr_emerg("Please enable two timers in HW\n"); pr_emerg("Please enable two timers in HW\n");
BUG(); BUG();
} }
#ifdef CONFIG_SELFMOD_TIMER pr_info("%s: irq=%d\n", timer->full_name, irq);
selfmod_function((int *) arr_func, timer_baseaddr);
#endif
pr_info("%s #0 at 0x%08x, irq=%d\n",
timer->name, timer_baseaddr, irq);
/* If there is clock-frequency property than use it */ /* If there is clock-frequency property than use it */
prop = of_get_property(timer, "clock-frequency", NULL); ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq);
if (prop) if (ret < 0)
timer_clock_freq = be32_to_cpup(prop);
else
timer_clock_freq = cpuinfo.cpu_clock_freq; timer_clock_freq = cpuinfo.cpu_clock_freq;
freq_div_hz = timer_clock_freq / HZ; freq_div_hz = timer_clock_freq / HZ;
...@@ -297,8 +260,8 @@ void __init time_init(void) ...@@ -297,8 +260,8 @@ void __init time_init(void)
#ifdef CONFIG_HEART_BEAT #ifdef CONFIG_HEART_BEAT
setup_heartbeat(); setup_heartbeat();
#endif #endif
microblaze_clocksource_init(); xilinx_clocksource_init();
microblaze_clockevent_init(); xilinx_clockevent_init();
timer_initialized = 1; timer_initialized = 1;
} }
...@@ -312,3 +275,6 @@ unsigned long long notrace sched_clock(void) ...@@ -312,3 +275,6 @@ unsigned long long notrace sched_clock(void)
} }
return 0; return 0;
} }
CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
xilinx_timer_init);
...@@ -657,67 +657,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar, ...@@ -657,67 +657,42 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
void pci_process_bridge_OF_ranges(struct pci_controller *hose, void pci_process_bridge_OF_ranges(struct pci_controller *hose,
struct device_node *dev, int primary) struct device_node *dev, int primary)
{ {
const u32 *ranges;
int rlen;
int pna = of_n_addr_cells(dev);
int np = pna + 5;
int memno = 0, isa_hole = -1; int memno = 0, isa_hole = -1;
u32 pci_space;
unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
unsigned long long isa_mb = 0; unsigned long long isa_mb = 0;
struct resource *res; struct resource *res;
struct of_pci_range range;
struct of_pci_range_parser parser;
pr_info("PCI host bridge %s %s ranges:\n", pr_info("PCI host bridge %s %s ranges:\n",
dev->full_name, primary ? "(primary)" : ""); dev->full_name, primary ? "(primary)" : "");
/* Get ranges property */ /* Check for ranges property */
ranges = of_get_property(dev, "ranges", &rlen); if (of_pci_range_parser_init(&parser, dev))
if (ranges == NULL)
return; return;
/* Parse it */
pr_debug("Parsing ranges property...\n"); pr_debug("Parsing ranges property...\n");
while ((rlen -= np * 4) >= 0) { for_each_of_pci_range(&parser, &range) {
/* Read next ranges element */ /* Read next ranges element */
pci_space = ranges[0];
pci_addr = of_read_number(ranges + 1, 2);
cpu_addr = of_translate_address(dev, ranges + 3);
size = of_read_number(ranges + pna + 3, 2);
pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ", pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
pci_space, pci_addr); range.pci_space, range.pci_addr);
pr_debug("cpu_addr:0x%016llx size:0x%016llx\n", pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
cpu_addr, size); range.cpu_addr, range.size);
ranges += np;
/* If we failed translation or got a zero-sized region /* If we failed translation or got a zero-sized region
* (some FW try to feed us with non sensical zero sized regions * (some FW try to feed us with non sensical zero sized regions
* such as power3 which look like some kind of attempt * such as power3 which look like some kind of attempt
* at exposing the VGA memory hole) * at exposing the VGA memory hole)
*/ */
if (cpu_addr == OF_BAD_ADDR || size == 0) if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
continue; continue;
/* Now consume following elements while they are contiguous */
for (; rlen >= np * sizeof(u32);
ranges += np, rlen -= np * 4) {
if (ranges[0] != pci_space)
break;
pci_next = of_read_number(ranges + 1, 2);
cpu_next = of_translate_address(dev, ranges + 3);
if (pci_next != pci_addr + size ||
cpu_next != cpu_addr + size)
break;
size += of_read_number(ranges + pna + 3, 2);
}
/* Act based on address space type */ /* Act based on address space type */
res = NULL; res = NULL;
switch ((pci_space >> 24) & 0x3) { switch (range.flags & IORESOURCE_TYPE_BITS) {
case 1: /* PCI IO space */ case IORESOURCE_IO:
pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n", pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
cpu_addr, cpu_addr + size - 1, pci_addr); range.cpu_addr, range.cpu_addr + range.size - 1,
range.pci_addr);
/* We support only one IO range */ /* We support only one IO range */
if (hose->pci_io_size) { if (hose->pci_io_size) {
...@@ -725,11 +700,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -725,11 +700,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
continue; continue;
} }
/* On 32 bits, limit I/O space to 16MB */ /* On 32 bits, limit I/O space to 16MB */
if (size > 0x01000000) if (range.size > 0x01000000)
size = 0x01000000; range.size = 0x01000000;
/* 32 bits needs to map IOs here */ /* 32 bits needs to map IOs here */
hose->io_base_virt = ioremap(cpu_addr, size); hose->io_base_virt = ioremap(range.cpu_addr,
range.size);
/* Expect trouble if pci_addr is not 0 */ /* Expect trouble if pci_addr is not 0 */
if (primary) if (primary)
...@@ -738,19 +714,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -738,19 +714,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
/* pci_io_size and io_base_phys always represent IO /* pci_io_size and io_base_phys always represent IO
* space starting at 0 so we factor in pci_addr * space starting at 0 so we factor in pci_addr
*/ */
hose->pci_io_size = pci_addr + size; hose->pci_io_size = range.pci_addr + range.size;
hose->io_base_phys = cpu_addr - pci_addr; hose->io_base_phys = range.cpu_addr - range.pci_addr;
/* Build resource */ /* Build resource */
res = &hose->io_resource; res = &hose->io_resource;
res->flags = IORESOURCE_IO; range.cpu_addr = range.pci_addr;
res->start = pci_addr;
break; break;
case 2: /* PCI Memory space */ case IORESOURCE_MEM:
case 3: /* PCI 64 bits Memory space */
pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n", pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
cpu_addr, cpu_addr + size - 1, pci_addr, range.cpu_addr, range.cpu_addr + range.size - 1,
(pci_space & 0x40000000) ? "Prefetch" : ""); range.pci_addr,
(range.pci_space & 0x40000000) ?
"Prefetch" : "");
/* We support only 3 memory ranges */ /* We support only 3 memory ranges */
if (memno >= 3) { if (memno >= 3) {
...@@ -758,13 +735,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -758,13 +735,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
continue; continue;
} }
/* Handles ISA memory hole space here */ /* Handles ISA memory hole space here */
if (pci_addr == 0) { if (range.pci_addr == 0) {
isa_mb = cpu_addr; isa_mb = range.cpu_addr;
isa_hole = memno; isa_hole = memno;
if (primary || isa_mem_base == 0) if (primary || isa_mem_base == 0)
isa_mem_base = cpu_addr; isa_mem_base = range.cpu_addr;
hose->isa_mem_phys = cpu_addr; hose->isa_mem_phys = range.cpu_addr;
hose->isa_mem_size = size; hose->isa_mem_size = range.size;
} }
/* We get the PCI/Mem offset from the first range or /* We get the PCI/Mem offset from the first range or
...@@ -772,30 +749,23 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -772,30 +749,23 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
* hole. If they don't match, bugger. * hole. If they don't match, bugger.
*/ */
if (memno == 0 || if (memno == 0 ||
(isa_hole >= 0 && pci_addr != 0 && (isa_hole >= 0 && range.pci_addr != 0 &&
hose->pci_mem_offset == isa_mb)) hose->pci_mem_offset == isa_mb))
hose->pci_mem_offset = cpu_addr - pci_addr; hose->pci_mem_offset = range.cpu_addr -
else if (pci_addr != 0 && range.pci_addr;
hose->pci_mem_offset != cpu_addr - pci_addr) { else if (range.pci_addr != 0 &&
hose->pci_mem_offset != range.cpu_addr -
range.pci_addr) {
pr_info(" \\--> Skipped (offset mismatch) !\n"); pr_info(" \\--> Skipped (offset mismatch) !\n");
continue; continue;
} }
/* Build resource */ /* Build resource */
res = &hose->mem_resources[memno++]; res = &hose->mem_resources[memno++];
res->flags = IORESOURCE_MEM;
if (pci_space & 0x40000000)
res->flags |= IORESOURCE_PREFETCH;
res->start = cpu_addr;
break; break;
} }
if (res != NULL) { if (res != NULL)
res->name = dev->full_name; of_pci_range_to_resource(&range, dev, res);
res->end = res->start + size - 1;
res->parent = NULL;
res->sibling = NULL;
res->child = NULL;
}
} }
/* If there's an ISA hole and the pci_mem_offset is -not- matching /* If there's an ISA hole and the pci_mem_offset is -not- matching
......
...@@ -18,28 +18,6 @@ config PLATFORM_GENERIC ...@@ -18,28 +18,6 @@ config PLATFORM_GENERIC
endchoice endchoice
config SELFMOD
bool "Use self modified code for intc/timer"
depends on NO_MMU
default n
help
This choice enables self-modified code for interrupt controller
and timer.
config SELFMOD_INTC
bool "Use self modified code for intc"
depends on SELFMOD
default y
help
This choice enables self-modified code for interrupt controller.
config SELFMOD_TIMER
bool "Use self modified code for timer"
depends on SELFMOD
default y
help
This choice enables self-modified code for timer.
config OPT_LIB_FUNCTION config OPT_LIB_FUNCTION
bool "Optimalized lib function" bool "Optimalized lib function"
default y default y
......
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