Microblaze patches for 3.12-rc1
PCI fixes Selfmod code removing Intc and timer fixes Adding new MB versions Minor fixes -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iEYEABECAAYFAlIpmwUACgkQykllyylKDCGuTACgi6LLlEhw+t8/kg7HIlT5FZDK 5roAn1mnev4didR4F8hbhcCag09vjJJu =P5in -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
5872c84027
@ -29,6 +29,7 @@ config MICROBLAZE
|
||||
select GENERIC_IDLE_POLL_SETUP
|
||||
select MODULES_USE_ELF_RELA
|
||||
select CLONE_BACKWARDS3
|
||||
select CLKSRC_OF
|
||||
|
||||
config SWAP
|
||||
def_bool n
|
||||
|
@ -72,7 +72,7 @@ all: linux.bin
|
||||
archclean:
|
||||
$(Q)$(MAKE) $(clean)=$(boot)
|
||||
|
||||
linux.bin linux.bin.gz: vmlinux
|
||||
linux.bin linux.bin.gz linux.bin.ub: vmlinux
|
||||
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
|
||||
|
||||
simpleImage.%: vmlinux
|
||||
@ -81,6 +81,7 @@ simpleImage.%: vmlinux
|
||||
define archhelp
|
||||
echo '* linux.bin - Create 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 ' - stripped elf with fdt blob'
|
||||
echo ' simpleImage.<dt>.unstrip - full ELF image with fdt blob'
|
||||
|
@ -2,12 +2,15 @@
|
||||
# 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
|
||||
|
||||
$(obj)/linux.bin: vmlinux FORCE
|
||||
$(call if_changed,objcopy)
|
||||
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
||||
|
||||
$(obj)/linux.bin.ub: $(obj)/linux.bin FORCE
|
||||
$(call if_changed,uimage)
|
||||
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
|
||||
|
||||
@ -22,8 +25,6 @@ quiet_cmd_strip = STRIP $@
|
||||
cmd_strip = $(STRIP) -K microblaze_start -K _end -K __log_buf \
|
||||
-K _fdt_start vmlinux -o $@
|
||||
|
||||
UIMAGE_IN = $@
|
||||
UIMAGE_OUT = $@.ub
|
||||
UIMAGE_LOADADDR = $(CONFIG_KERNEL_BASE_ADDR)
|
||||
|
||||
$(obj)/simpleImage.%: vmlinux FORCE
|
||||
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
CFLAGS_REMOVE_timer.o = -pg
|
||||
CFLAGS_REMOVE_intc.o = -pg
|
||||
CFLAGS_REMOVE_early_printk.o = -pg
|
||||
CFLAGS_REMOVE_selfmod.o = -pg
|
||||
CFLAGS_REMOVE_heartbeat.o = -pg
|
||||
CFLAGS_REMOVE_ftrace.o = -pg
|
||||
CFLAGS_REMOVE_process.o = -pg
|
||||
@ -23,7 +22,6 @@ obj-y += dma.o exceptions.o \
|
||||
obj-y += cpu/
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
|
||||
obj-$(CONFIG_SELFMOD) += selfmod.o
|
||||
obj-$(CONFIG_HEART_BEAT) += heartbeat.o
|
||||
obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
|
||||
obj-$(CONFIG_MMU) += misc.o
|
||||
|
@ -39,6 +39,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
|
||||
{"8.30.a", 0x17},
|
||||
{"8.40.a", 0x18},
|
||||
{"8.40.b", 0x19},
|
||||
{"9.0", 0x1b},
|
||||
{"9.1", 0x1d},
|
||||
{NULL, 0},
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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) 2006 Atmark Techno, Inc.
|
||||
*
|
||||
@ -8,23 +9,15 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irqdomain.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/page.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bug.h>
|
||||
|
||||
#include <asm/prom.h>
|
||||
#include <asm/irq.h>
|
||||
#include "../../drivers/irqchip/irqchip.h"
|
||||
|
||||
#ifdef CONFIG_SELFMOD_INTC
|
||||
#include <asm/selfmod.h>
|
||||
#define INTC_BASE BARRIER_BASE_ADDR
|
||||
#else
|
||||
static unsigned int intc_baseaddr;
|
||||
#define INTC_BASE intc_baseaddr
|
||||
#endif
|
||||
static void __iomem *intc_baseaddr;
|
||||
|
||||
/* No one else should require these constants, so define them locally here. */
|
||||
#define ISR 0x00 /* Interrupt Status Register */
|
||||
@ -50,21 +43,21 @@ static void intc_enable_or_unmask(struct irq_data *d)
|
||||
* acks the irq before calling the interrupt handler
|
||||
*/
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
@ -72,8 +65,8 @@ static void intc_mask_ack(struct irq_data *d)
|
||||
unsigned long mask = 1 << d->hwirq;
|
||||
|
||||
pr_debug("disable_and_ack: %ld\n", d->hwirq);
|
||||
out_be32(INTC_BASE + CIE, mask);
|
||||
out_be32(INTC_BASE + IAR, mask);
|
||||
out_be32(intc_baseaddr + CIE, mask);
|
||||
out_be32(intc_baseaddr + IAR, mask);
|
||||
}
|
||||
|
||||
static struct irq_chip intc_dev = {
|
||||
@ -90,7 +83,7 @@ unsigned int get_irq(void)
|
||||
{
|
||||
unsigned int hwirq, irq = -1;
|
||||
|
||||
hwirq = in_be32(INTC_BASE + IVR);
|
||||
hwirq = in_be32(intc_baseaddr + IVR);
|
||||
if (hwirq != -1U)
|
||||
irq = irq_find_mapping(root_domain, hwirq);
|
||||
|
||||
@ -120,40 +113,32 @@ static const struct irq_domain_ops xintc_irq_domain_ops = {
|
||||
.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;
|
||||
struct device_node *intc = NULL;
|
||||
#ifdef CONFIG_SELFMOD_INTC
|
||||
unsigned int intc_baseaddr = 0;
|
||||
static int arr_func[] = {
|
||||
(int)&get_irq,
|
||||
(int)&intc_enable_or_unmask,
|
||||
(int)&intc_disable_or_mask,
|
||||
(int)&intc_mask_ack,
|
||||
(int)&intc_ack,
|
||||
(int)&intc_end,
|
||||
0
|
||||
};
|
||||
#endif
|
||||
intc = of_find_compatible_node(NULL, NULL, "xlnx,xps-intc-1.00.a");
|
||||
BUG_ON(!intc);
|
||||
int ret;
|
||||
|
||||
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));
|
||||
intc_baseaddr = of_iomap(intc, 0);
|
||||
BUG_ON(!intc_baseaddr);
|
||||
|
||||
ret = of_property_read_u32(intc, "xlnx,num-intr-inputs", &nr_irq);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: unable to read xlnx,num-intr-inputs\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(intc, "xlnx,kind-of-intr", &intr_mask);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: unable to read xlnx,kind-of-intr\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intr_mask =
|
||||
be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL));
|
||||
if (intr_mask > (u32)((1ULL << nr_irq) - 1))
|
||||
pr_info(" ERROR: Mismatch in kind-of-intr param\n");
|
||||
|
||||
#ifdef CONFIG_SELFMOD_INTC
|
||||
selfmod_function((int *) arr_func, intc_baseaddr);
|
||||
#endif
|
||||
pr_info("%s #0 at 0x%08x, num_irq=%d, edge=0x%x\n",
|
||||
intc->name, intc_baseaddr, nr_irq, intr_mask);
|
||||
pr_info("%s: num_irq=%d, edge=0x%x\n",
|
||||
intc->full_name, nr_irq, intr_mask);
|
||||
|
||||
/*
|
||||
* Disable all external interrupts until they are
|
||||
@ -174,4 +159,8 @@ void __init init_IRQ(void)
|
||||
(void *)intr_mask);
|
||||
|
||||
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 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqchip.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <asm/prom.h>
|
||||
|
||||
static u32 concurrent_irq;
|
||||
|
||||
@ -47,3 +45,9 @@ void __irq_entry do_IRQ(struct pt_regs *regs)
|
||||
set_irq_regs(old_regs);
|
||||
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)
|
||||
pr_notice("Reset GPIO unavailable - halting!\n");
|
||||
}
|
||||
#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)
|
||||
{
|
||||
return;
|
||||
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
* 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 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/cpu.h>
|
||||
@ -68,10 +69,6 @@ void __init setup_arch(char **cmdline_p)
|
||||
|
||||
xilinx_pci_init();
|
||||
|
||||
#if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER)
|
||||
pr_notice("Self modified code enable\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_VT
|
||||
#if defined(CONFIG_XILINX_CONSOLE)
|
||||
conswitchp = &xil_con;
|
||||
@ -196,6 +193,11 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
|
||||
per_cpu(CURRENT_SAVE, 0) = (unsigned long)current;
|
||||
}
|
||||
|
||||
void __init time_init(void)
|
||||
{
|
||||
clocksource_of_init();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *of_debugfs_root;
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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) 2006 Atmark Techno, Inc.
|
||||
*
|
||||
@ -8,34 +9,16 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/profile.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <asm/cpuinfo.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/cnt32_to_63.h>
|
||||
|
||||
#ifdef CONFIG_SELFMOD_TIMER
|
||||
#include <asm/selfmod.h>
|
||||
#define TIMER_BASE BARRIER_BASE_ADDR
|
||||
#else
|
||||
static unsigned int timer_baseaddr;
|
||||
#define TIMER_BASE timer_baseaddr
|
||||
#endif
|
||||
static void __iomem *timer_baseaddr;
|
||||
|
||||
static unsigned int freq_div_hz;
|
||||
static unsigned int timer_clock_freq;
|
||||
@ -59,19 +42,21 @@ static unsigned int timer_clock_freq;
|
||||
#define TCSR_PWMA (1<<9)
|
||||
#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)
|
||||
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 */
|
||||
out_be32(TIMER_BASE + TCSR0, TCSR_LOAD);
|
||||
out_be32(timer_baseaddr + TCSR0, TCSR_LOAD);
|
||||
|
||||
/* see timer data sheet for detail
|
||||
* !ENALL - don't enable 'em all
|
||||
@ -86,38 +71,39 @@ static inline void microblaze_timer0_start_periodic(unsigned long load_val)
|
||||
* UDT - set the timer as down counter
|
||||
* !MDT0 - generate mode
|
||||
*/
|
||||
out_be32(TIMER_BASE + TCSR0,
|
||||
out_be32(timer_baseaddr + TCSR0,
|
||||
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)
|
||||
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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
pr_debug("%s: next event, delta %x\n", __func__, (u32)delta);
|
||||
microblaze_timer0_start_oneshot(delta);
|
||||
xilinx_timer0_start_oneshot(delta);
|
||||
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)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
pr_info("%s: periodic\n", __func__);
|
||||
microblaze_timer0_start_periodic(freq_div_hz);
|
||||
xilinx_timer0_start_periodic(freq_div_hz);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
pr_info("%s: oneshot\n", __func__);
|
||||
@ -127,7 +113,7 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
|
||||
break;
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
pr_info("%s: shutdown\n", __func__);
|
||||
microblaze_timer0_stop();
|
||||
xilinx_timer0_stop();
|
||||
break;
|
||||
case CLOCK_EVT_MODE_RESUME:
|
||||
pr_info("%s: resume\n", __func__);
|
||||
@ -135,23 +121,23 @@ static void microblaze_timer_set_mode(enum clock_event_mode mode,
|
||||
}
|
||||
}
|
||||
|
||||
static struct clock_event_device clockevent_microblaze_timer = {
|
||||
.name = "microblaze_clockevent",
|
||||
static struct clock_event_device clockevent_xilinx_timer = {
|
||||
.name = "xilinx_clockevent",
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
|
||||
.shift = 8,
|
||||
.rating = 300,
|
||||
.set_next_event = microblaze_timer_set_next_event,
|
||||
.set_mode = microblaze_timer_set_mode,
|
||||
.set_next_event = xilinx_timer_set_next_event,
|
||||
.set_mode = xilinx_timer_set_mode,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
struct clock_event_device *evt = &clockevent_microblaze_timer;
|
||||
struct clock_event_device *evt = &clockevent_xilinx_timer;
|
||||
#ifdef CONFIG_HEART_BEAT
|
||||
heartbeat();
|
||||
#endif
|
||||
@ -164,73 +150,74 @@ static struct irqaction timer_irqaction = {
|
||||
.handler = timer_interrupt,
|
||||
.flags = IRQF_DISABLED | IRQF_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,
|
||||
clockevent_microblaze_timer.shift);
|
||||
clockevent_microblaze_timer.max_delta_ns =
|
||||
clockevent_delta2ns((u32)~0, &clockevent_microblaze_timer);
|
||||
clockevent_microblaze_timer.min_delta_ns =
|
||||
clockevent_delta2ns(1, &clockevent_microblaze_timer);
|
||||
clockevent_microblaze_timer.cpumask = cpumask_of(0);
|
||||
clockevents_register_device(&clockevent_microblaze_timer);
|
||||
clockevent_xilinx_timer.shift);
|
||||
clockevent_xilinx_timer.max_delta_ns =
|
||||
clockevent_delta2ns((u32)~0, &clockevent_xilinx_timer);
|
||||
clockevent_xilinx_timer.min_delta_ns =
|
||||
clockevent_delta2ns(1, &clockevent_xilinx_timer);
|
||||
clockevent_xilinx_timer.cpumask = cpumask_of(0);
|
||||
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 */
|
||||
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,
|
||||
};
|
||||
|
||||
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 = {
|
||||
.read = microblaze_cc_read,
|
||||
static struct cyclecounter xilinx_cc = {
|
||||
.read = xilinx_cc_read,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
.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,
|
||||
microblaze_cc.shift);
|
||||
xilinx_cc.mult = div_sc(timer_clock_freq, NSEC_PER_SEC,
|
||||
xilinx_cc.shift);
|
||||
|
||||
timecounter_init(µblaze_tc, µblaze_cc, sched_clock());
|
||||
timecounter_init(&xilinx_tc, &xilinx_cc, sched_clock());
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct clocksource clocksource_microblaze = {
|
||||
.name = "microblaze_clocksource",
|
||||
.name = "xilinx_clocksource",
|
||||
.rating = 300,
|
||||
.read = microblaze_read,
|
||||
.read = xilinx_read,
|
||||
.mask = CLOCKSOURCE_MASK(32),
|
||||
.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))
|
||||
panic("failed to register clocksource");
|
||||
|
||||
/* 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 */
|
||||
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 */
|
||||
init_microblaze_timecounter();
|
||||
init_xilinx_timecounter();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -240,55 +227,31 @@ static int __init microblaze_clocksource_init(void)
|
||||
*/
|
||||
static int timer_initialized;
|
||||
|
||||
void __init time_init(void)
|
||||
static void __init xilinx_timer_init(struct device_node *timer)
|
||||
{
|
||||
u32 irq;
|
||||
u32 timer_num = 1;
|
||||
struct device_node *timer = NULL;
|
||||
const void *prop;
|
||||
#ifdef CONFIG_SELFMOD_TIMER
|
||||
unsigned int timer_baseaddr = 0;
|
||||
int arr_func[] = {
|
||||
(int)µblaze_read,
|
||||
(int)&timer_interrupt,
|
||||
(int)µblaze_clocksource_init,
|
||||
(int)µblaze_timer_set_mode,
|
||||
(int)µblaze_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");
|
||||
int ret;
|
||||
|
||||
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);
|
||||
timer_num = be32_to_cpup(of_get_property(timer,
|
||||
"xlnx,one-timer-only", NULL));
|
||||
if (timer_num) {
|
||||
pr_emerg("Please enable two timers in HW\n");
|
||||
timer_baseaddr = of_iomap(timer, 0);
|
||||
if (!timer_baseaddr) {
|
||||
pr_err("ERROR: invalid timer base address\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SELFMOD_TIMER
|
||||
selfmod_function((int *) arr_func, timer_baseaddr);
|
||||
#endif
|
||||
pr_info("%s #0 at 0x%08x, irq=%d\n",
|
||||
timer->name, timer_baseaddr, irq);
|
||||
irq = irq_of_parse_and_map(timer, 0);
|
||||
|
||||
of_property_read_u32(timer, "xlnx,one-timer-only", &timer_num);
|
||||
if (timer_num) {
|
||||
pr_emerg("Please enable two timers in HW\n");
|
||||
BUG();
|
||||
}
|
||||
|
||||
pr_info("%s: irq=%d\n", timer->full_name, irq);
|
||||
|
||||
/* If there is clock-frequency property than use it */
|
||||
prop = of_get_property(timer, "clock-frequency", NULL);
|
||||
if (prop)
|
||||
timer_clock_freq = be32_to_cpup(prop);
|
||||
else
|
||||
ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq);
|
||||
if (ret < 0)
|
||||
timer_clock_freq = cpuinfo.cpu_clock_freq;
|
||||
|
||||
freq_div_hz = timer_clock_freq / HZ;
|
||||
@ -297,8 +260,8 @@ void __init time_init(void)
|
||||
#ifdef CONFIG_HEART_BEAT
|
||||
setup_heartbeat();
|
||||
#endif
|
||||
microblaze_clocksource_init();
|
||||
microblaze_clockevent_init();
|
||||
xilinx_clocksource_init();
|
||||
xilinx_clockevent_init();
|
||||
timer_initialized = 1;
|
||||
}
|
||||
|
||||
@ -312,3 +275,6 @@ unsigned long long notrace sched_clock(void)
|
||||
}
|
||||
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,
|
||||
void pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
||||
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;
|
||||
u32 pci_space;
|
||||
unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
|
||||
unsigned long long isa_mb = 0;
|
||||
struct resource *res;
|
||||
struct of_pci_range range;
|
||||
struct of_pci_range_parser parser;
|
||||
|
||||
pr_info("PCI host bridge %s %s ranges:\n",
|
||||
dev->full_name, primary ? "(primary)" : "");
|
||||
|
||||
/* Get ranges property */
|
||||
ranges = of_get_property(dev, "ranges", &rlen);
|
||||
if (ranges == NULL)
|
||||
/* Check for ranges property */
|
||||
if (of_pci_range_parser_init(&parser, dev))
|
||||
return;
|
||||
|
||||
/* Parse it */
|
||||
pr_debug("Parsing ranges property...\n");
|
||||
while ((rlen -= np * 4) >= 0) {
|
||||
for_each_of_pci_range(&parser, &range) {
|
||||
/* 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 ",
|
||||
pci_space, pci_addr);
|
||||
range.pci_space, range.pci_addr);
|
||||
pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
|
||||
cpu_addr, size);
|
||||
|
||||
ranges += np;
|
||||
range.cpu_addr, range.size);
|
||||
|
||||
/* If we failed translation or got a zero-sized region
|
||||
* (some FW try to feed us with non sensical zero sized regions
|
||||
* such as power3 which look like some kind of attempt
|
||||
* 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;
|
||||
|
||||
/* 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 */
|
||||
res = NULL;
|
||||
switch ((pci_space >> 24) & 0x3) {
|
||||
case 1: /* PCI IO space */
|
||||
switch (range.flags & IORESOURCE_TYPE_BITS) {
|
||||
case IORESOURCE_IO:
|
||||
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 */
|
||||
if (hose->pci_io_size) {
|
||||
@ -725,11 +700,12 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
||||
continue;
|
||||
}
|
||||
/* On 32 bits, limit I/O space to 16MB */
|
||||
if (size > 0x01000000)
|
||||
size = 0x01000000;
|
||||
if (range.size > 0x01000000)
|
||||
range.size = 0x01000000;
|
||||
|
||||
/* 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 */
|
||||
if (primary)
|
||||
@ -738,19 +714,20 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
||||
/* pci_io_size and io_base_phys always represent IO
|
||||
* space starting at 0 so we factor in pci_addr
|
||||
*/
|
||||
hose->pci_io_size = pci_addr + size;
|
||||
hose->io_base_phys = cpu_addr - pci_addr;
|
||||
hose->pci_io_size = range.pci_addr + range.size;
|
||||
hose->io_base_phys = range.cpu_addr - range.pci_addr;
|
||||
|
||||
/* Build resource */
|
||||
res = &hose->io_resource;
|
||||
res->flags = IORESOURCE_IO;
|
||||
res->start = pci_addr;
|
||||
range.cpu_addr = range.pci_addr;
|
||||
|
||||
break;
|
||||
case 2: /* PCI Memory space */
|
||||
case 3: /* PCI 64 bits Memory space */
|
||||
case IORESOURCE_MEM:
|
||||
pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
|
||||
cpu_addr, cpu_addr + size - 1, pci_addr,
|
||||
(pci_space & 0x40000000) ? "Prefetch" : "");
|
||||
range.cpu_addr, range.cpu_addr + range.size - 1,
|
||||
range.pci_addr,
|
||||
(range.pci_space & 0x40000000) ?
|
||||
"Prefetch" : "");
|
||||
|
||||
/* We support only 3 memory ranges */
|
||||
if (memno >= 3) {
|
||||
@ -758,13 +735,13 @@ void pci_process_bridge_OF_ranges(struct pci_controller *hose,
|
||||
continue;
|
||||
}
|
||||
/* Handles ISA memory hole space here */
|
||||
if (pci_addr == 0) {
|
||||
isa_mb = cpu_addr;
|
||||
if (range.pci_addr == 0) {
|
||||
isa_mb = range.cpu_addr;
|
||||
isa_hole = memno;
|
||||
if (primary || isa_mem_base == 0)
|
||||
isa_mem_base = cpu_addr;
|
||||
hose->isa_mem_phys = cpu_addr;
|
||||
hose->isa_mem_size = size;
|
||||
isa_mem_base = range.cpu_addr;
|
||||
hose->isa_mem_phys = range.cpu_addr;
|
||||
hose->isa_mem_size = range.size;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
* hole. If they don't match, bugger.
|
||||
*/
|
||||
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 = cpu_addr - pci_addr;
|
||||
else if (pci_addr != 0 &&
|
||||
hose->pci_mem_offset != cpu_addr - pci_addr) {
|
||||
hose->pci_mem_offset = range.cpu_addr -
|
||||
range.pci_addr;
|
||||
else if (range.pci_addr != 0 &&
|
||||
hose->pci_mem_offset != range.cpu_addr -
|
||||
range.pci_addr) {
|
||||
pr_info(" \\--> Skipped (offset mismatch) !\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Build resource */
|
||||
res = &hose->mem_resources[memno++];
|
||||
res->flags = IORESOURCE_MEM;
|
||||
if (pci_space & 0x40000000)
|
||||
res->flags |= IORESOURCE_PREFETCH;
|
||||
res->start = cpu_addr;
|
||||
break;
|
||||
}
|
||||
if (res != NULL) {
|
||||
res->name = dev->full_name;
|
||||
res->end = res->start + size - 1;
|
||||
res->parent = NULL;
|
||||
res->sibling = NULL;
|
||||
res->child = NULL;
|
||||
}
|
||||
if (res != NULL)
|
||||
of_pci_range_to_resource(&range, dev, res);
|
||||
}
|
||||
|
||||
/* If there's an ISA hole and the pci_mem_offset is -not- matching
|
||||
|
@ -18,28 +18,6 @@ config PLATFORM_GENERIC
|
||||
|
||||
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
|
||||
bool "Optimalized lib function"
|
||||
default y
|
||||
|
Loading…
Reference in New Issue
Block a user