Commit 47b170af authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'sh-for-linus' of git://github.com/pmundt/linux-sh

Pull SuperH updates from Paul Mundt:

 - Migration off of old-style dynamic IRQ API.

 - irqdomain and generic irq chip propagation.

 - div4/6 clock consolidation, another step towards co-existing with the
   common struct clk infrastructure.

 - Extensive PFC rework
   - Decoupling GPIO from pin state.
   - Initial pinctrl support to facilitate incremental migration off of
     legacy pinmux.
   - gpiolib support made optional, and made pinctrl-backed.

* tag 'sh-for-linus' of git://github.com/pmundt/linux-sh: (38 commits)
  sh: pfc: pin config get/set support.
  sh: pfc: Prefer DRV_NAME over KBUILD_MODNAME.
  sh: pfc: pinctrl legacy group support.
  sh: pfc: Ignore pinmux GPIOs with invalid enum IDs.
  sh: pfc: Export pinctrl binding init symbol.
  sh: pfc: Error out on pinctrl init resolution failure.
  sh: pfc: Make pr_fmt consistent across pfc drivers.
  sh: pfc: pinctrl legacy function support.
  sh: pfc: Rudimentary pinctrl-backed GPIO support.
  sh: pfc: Dumb GPIO stringification.
  sh: pfc: Shuffle PFC support core.
  sh: pfc: Verify pin type encoding size at build time.
  sh: pfc: Kill off unused pinmux bias flags.
  sh: pfc: Make gpio chip support optional where possible.
  sh: pfc: Split out gpio chip support.
  sh64: Fix up section mismatch warnings.
  sh64: Attempt to make reserved insn trap handler resemble C.
  sh: Consolidate die definitions for trap handlers.
  sh64: Kill off old exception debugging helpers.
  sh64: Use generic unaligned access control/counters.
  ...
parents 83c7f722 9ff561fd
...@@ -60,6 +60,7 @@ config SUPERH32 ...@@ -60,6 +60,7 @@ config SUPERH32
config SUPERH64 config SUPERH64
def_bool ARCH = "sh64" def_bool ARCH = "sh64"
select KALLSYMS
config ARCH_DEFCONFIG config ARCH_DEFCONFIG
string string
......
...@@ -44,6 +44,8 @@ config SH_7721_SOLUTION_ENGINE ...@@ -44,6 +44,8 @@ config SH_7721_SOLUTION_ENGINE
config SH_7722_SOLUTION_ENGINE config SH_7722_SOLUTION_ENGINE
bool "SolutionEngine7722" bool "SolutionEngine7722"
select SOLUTION_ENGINE select SOLUTION_ENGINE
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
depends on CPU_SUBTYPE_SH7722 depends on CPU_SUBTYPE_SH7722
help help
Select 7722 SolutionEngine if configuring for a Hitachi SH772 Select 7722 SolutionEngine if configuring for a Hitachi SH772
...@@ -80,6 +82,8 @@ config SH_7780_SOLUTION_ENGINE ...@@ -80,6 +82,8 @@ config SH_7780_SOLUTION_ENGINE
config SH_7343_SOLUTION_ENGINE config SH_7343_SOLUTION_ENGINE
bool "SolutionEngine7343" bool "SolutionEngine7343"
select SOLUTION_ENGINE select SOLUTION_ENGINE
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
depends on CPU_SUBTYPE_SH7343 depends on CPU_SUBTYPE_SH7343
help help
Select 7343 SolutionEngine if configuring for a Hitachi Select 7343 SolutionEngine if configuring for a Hitachi
...@@ -295,6 +299,7 @@ config SH_X3PROTO ...@@ -295,6 +299,7 @@ config SH_X3PROTO
bool "SH-X3 Prototype board" bool "SH-X3 Prototype board"
depends on CPU_SUBTYPE_SHX3 depends on CPU_SUBTYPE_SHX3
select NO_IOPORT if !PCI select NO_IOPORT if !PCI
select IRQ_DOMAIN
config SH_MAGIC_PANEL_R2 config SH_MAGIC_PANEL_R2
bool "Magic Panel R2" bool "Magic Panel R2"
......
...@@ -8,10 +8,11 @@ ...@@ -8,10 +8,11 @@
* This file is part of the LinuxDC project (www.linuxdc.org) * This file is part of the LinuxDC project (www.linuxdc.org)
* Released under the terms of the GNU GPL v2.0 * Released under the terms of the GNU GPL v2.0
*/ */
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/irq.h> #include <linux/irq.h>
#include <linux/export.h>
#include <linux/err.h>
#include <mach/sysasic.h> #include <mach/sysasic.h>
/* /*
...@@ -141,26 +142,15 @@ int systemasic_irq_demux(int irq) ...@@ -141,26 +142,15 @@ int systemasic_irq_demux(int irq)
void systemasic_irq_init(void) void systemasic_irq_init(void)
{ {
int i, nid = cpu_to_node(boot_cpu_data); int irq_base, i;
/* Assign all virtual IRQs to the System ASIC int. handler */
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++) {
unsigned int irq;
irq = create_irq_nr(i, nid);
if (unlikely(irq == 0)) {
pr_err("%s: failed hooking irq %d for systemasic\n",
__func__, i);
return;
}
if (unlikely(irq != i)) { irq_base = irq_alloc_descs(HW_EVENT_IRQ_BASE, HW_EVENT_IRQ_BASE,
pr_err("%s: got irq %d but wanted %d, bailing.\n", HW_EVENT_IRQ_MAX - HW_EVENT_IRQ_BASE, -1);
__func__, irq, i); if (IS_ERR_VALUE(irq_base)) {
destroy_irq(irq); pr_err("%s: failed hooking irqs\n", __func__);
return; return;
} }
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
irq_set_chip_and_handler(i, &systemasic_int, handle_level_irq); irq_set_chip_and_handler(i, &systemasic_int, handle_level_irq);
}
} }
/* /*
* linux/arch/sh/boards/se/7343/irq.c * Hitachi UL SolutionEngine 7343 FPGA IRQ Support.
* *
* Copyright (C) 2008 Yoshihiro Shimoda * Copyright (C) 2008 Yoshihiro Shimoda
* Copyright (C) 2012 Paul Mundt
* *
* Based on linux/arch/sh/boards/se/7722/irq.c * Based on linux/arch/sh/boards/se/7343/irq.c
* Copyright (C) 2007 Nobuhiro Iwamatsu * Copyright (C) 2007 Nobuhiro Iwamatsu
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
*/ */
#define DRV_NAME "SE7343-FPGA"
#define pr_fmt(fmt) DRV_NAME ": " fmt
#define irq_reg_readl ioread16
#define irq_reg_writel iowrite16
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/sizes.h>
#include <mach-se/mach/se7343.h> #include <mach-se/mach/se7343.h>
unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, }; #define PA_CPLD_BASE_ADDR 0x11400000
#define PA_CPLD_ST_REG 0x08 /* CPLD Interrupt status register */
#define PA_CPLD_IMSK_REG 0x0a /* CPLD Interrupt mask register */
static void disable_se7343_irq(struct irq_data *data) static void __iomem *se7343_irq_regs;
{ struct irq_domain *se7343_irq_domain;
unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
}
static void enable_se7343_irq(struct irq_data *data) static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
{ {
unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data); struct irq_data *data = irq_get_irq_data(irq);
__raw_writew(__raw_readw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK); struct irq_chip *chip = irq_data_get_irq_chip(data);
} unsigned long mask;
int bit;
static struct irq_chip se7343_irq_chip __read_mostly = { chip->irq_mask_ack(data);
.name = "SE7343-FPGA",
.irq_mask = disable_se7343_irq,
.irq_unmask = enable_se7343_irq,
};
static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc) mask = ioread16(se7343_irq_regs + PA_CPLD_ST_REG);
for_each_set_bit(bit, &mask, SE7343_FPGA_IRQ_NR)
generic_handle_irq(irq_linear_revmap(se7343_irq_domain, bit));
chip->irq_unmask(data);
}
static void __init se7343_domain_init(void)
{ {
unsigned short intv = __raw_readw(PA_CPLD_ST); int i;
unsigned int ext_irq = 0;
intv &= (1 << SE7343_FPGA_IRQ_NR) - 1; se7343_irq_domain = irq_domain_add_linear(NULL, SE7343_FPGA_IRQ_NR,
&irq_domain_simple_ops, NULL);
if (unlikely(!se7343_irq_domain)) {
printk("Failed to get IRQ domain\n");
return;
}
for (; intv; intv >>= 1, ext_irq++) { for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) {
if (!(intv & 1)) int irq = irq_create_mapping(se7343_irq_domain, i);
continue;
generic_handle_irq(se7343_fpga_irq[ext_irq]); if (unlikely(irq == 0)) {
printk("Failed to allocate IRQ %d\n", i);
return;
}
} }
} }
/* static void __init se7343_gc_init(void)
* Initialize IRQ setting
*/
void __init init_7343se_IRQ(void)
{ {
int i, irq; struct irq_chip_generic *gc;
struct irq_chip_type *ct;
unsigned int irq_base;
__raw_writew(0, PA_CPLD_IMSK); /* disable all irqs */ irq_base = irq_linear_revmap(se7343_irq_domain, 0);
__raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */
for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) { gc = irq_alloc_generic_chip(DRV_NAME, 1, irq_base, se7343_irq_regs,
irq = create_irq(); handle_level_irq);
if (irq < 0) if (unlikely(!gc))
return; return;
se7343_fpga_irq[i] = irq;
irq_set_chip_and_handler_name(se7343_fpga_irq[i], ct = gc->chip_types;
&se7343_irq_chip, ct->chip.irq_mask = irq_gc_mask_set_bit;
handle_level_irq, ct->chip.irq_unmask = irq_gc_mask_clr_bit;
"level");
irq_set_chip_data(se7343_fpga_irq[i], (void *)i); ct->regs.mask = PA_CPLD_IMSK_REG;
}
irq_setup_generic_chip(gc, IRQ_MSK(SE7343_FPGA_IRQ_NR),
IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
irq_set_chained_handler(IRQ0_IRQ, se7343_irq_demux); irq_set_chained_handler(IRQ0_IRQ, se7343_irq_demux);
irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
irq_set_chained_handler(IRQ1_IRQ, se7343_irq_demux); irq_set_chained_handler(IRQ1_IRQ, se7343_irq_demux);
irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
irq_set_chained_handler(IRQ4_IRQ, se7343_irq_demux); irq_set_chained_handler(IRQ4_IRQ, se7343_irq_demux);
irq_set_irq_type(IRQ4_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ4_IRQ, IRQ_TYPE_LEVEL_LOW);
irq_set_chained_handler(IRQ5_IRQ, se7343_irq_demux); irq_set_chained_handler(IRQ5_IRQ, se7343_irq_demux);
irq_set_irq_type(IRQ5_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ5_IRQ, IRQ_TYPE_LEVEL_LOW);
} }
/*
* Initialize IRQ setting
*/
void __init init_7343se_IRQ(void)
{
se7343_irq_regs = ioremap(PA_CPLD_BASE_ADDR, SZ_16);
if (unlikely(!se7343_irq_regs)) {
pr_err("Failed to remap CPLD\n");
return;
}
/*
* All FPGA IRQs disabled by default
*/
iowrite16(0, se7343_irq_regs + PA_CPLD_IMSK_REG);
__raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */
se7343_domain_init();
se7343_gc_init();
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/serial_reg.h> #include <linux/serial_reg.h>
#include <linux/usb/isp116x.h> #include <linux/usb/isp116x.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/irqdomain.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <mach-se/mach/se7343.h> #include <mach-se/mach/se7343.h>
#include <asm/heartbeat.h> #include <asm/heartbeat.h>
...@@ -145,11 +146,12 @@ static struct platform_device *sh7343se_platform_devices[] __initdata = { ...@@ -145,11 +146,12 @@ static struct platform_device *sh7343se_platform_devices[] __initdata = {
static int __init sh7343se_devices_setup(void) static int __init sh7343se_devices_setup(void)
{ {
/* Wire-up dynamic vectors */ /* Wire-up dynamic vectors */
serial_platform_data[0].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTA]; serial_platform_data[0].irq = irq_find_mapping(se7343_irq_domain,
serial_platform_data[1].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTB]; SE7343_FPGA_IRQ_UARTA);
serial_platform_data[1].irq = irq_find_mapping(se7343_irq_domain,
SE7343_FPGA_IRQ_UARTB);
usb_resources[2].start = usb_resources[2].end = usb_resources[2].start = usb_resources[2].end =
se7343_fpga_irq[SE7343_FPGA_IRQ_USB]; irq_find_mapping(se7343_irq_domain, SE7343_FPGA_IRQ_USB);
return platform_add_devices(sh7343se_platform_devices, return platform_add_devices(sh7343se_platform_devices,
ARRAY_SIZE(sh7343se_platform_devices)); ARRAY_SIZE(sh7343se_platform_devices));
......
/* /*
* linux/arch/sh/boards/se/7722/irq.c * Hitachi UL SolutionEngine 7722 FPGA IRQ Support.
* *
* Copyright (C) 2007 Nobuhiro Iwamatsu * Copyright (C) 2007 Nobuhiro Iwamatsu
* * Copyright (C) 2012 Paul Mundt
* Hitachi UL SolutionEngine 7722 Support.
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
* for more details. * for more details.
*/ */
#define DRV_NAME "SE7722-FPGA"
#define pr_fmt(fmt) DRV_NAME ": " fmt
#define irq_reg_readl ioread16
#define irq_reg_writel iowrite16
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/irq.h> #include <linux/irqdomain.h>
#include <asm/io.h> #include <linux/io.h>
#include <linux/err.h>
#include <asm/sizes.h>
#include <mach-se/mach/se7722.h> #include <mach-se/mach/se7722.h>
unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, }; #define IRQ01_BASE_ADDR 0x11800000
#define IRQ01_MODE_REG 0
#define IRQ01_STS_REG 4
#define IRQ01_MASK_REG 8
static void disable_se7722_irq(struct irq_data *data) static void __iomem *se7722_irq_regs;
{ struct irq_domain *se7722_irq_domain;
unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data);
__raw_writew(__raw_readw(IRQ01_MASK) | 1 << bit, IRQ01_MASK);
}
static void enable_se7722_irq(struct irq_data *data) static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc)
{ {
unsigned int bit = (unsigned int)irq_data_get_irq_chip_data(data); struct irq_data *data = irq_get_irq_data(irq);
__raw_writew(__raw_readw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK); struct irq_chip *chip = irq_data_get_irq_chip(data);
} unsigned long mask;
int bit;
static struct irq_chip se7722_irq_chip __read_mostly = { chip->irq_mask_ack(data);
.name = "SE7722-FPGA",
.irq_mask = disable_se7722_irq,
.irq_unmask = enable_se7722_irq,
};
static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) mask = ioread16(se7722_irq_regs + IRQ01_STS_REG);
for_each_set_bit(bit, &mask, SE7722_FPGA_IRQ_NR)
generic_handle_irq(irq_linear_revmap(se7722_irq_domain, bit));
chip->irq_unmask(data);
}
static void __init se7722_domain_init(void)
{ {
unsigned short intv = __raw_readw(IRQ01_STS); int i;
unsigned int ext_irq = 0;
intv &= (1 << SE7722_FPGA_IRQ_NR) - 1; se7722_irq_domain = irq_domain_add_linear(NULL, SE7722_FPGA_IRQ_NR,
&irq_domain_simple_ops, NULL);
if (unlikely(!se7722_irq_domain)) {
printk("Failed to get IRQ domain\n");
return;
}
for (; intv; intv >>= 1, ext_irq++) { for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) {
if (!(intv & 1)) int irq = irq_create_mapping(se7722_irq_domain, i);
continue;
generic_handle_irq(se7722_fpga_irq[ext_irq]); if (unlikely(irq == 0)) {
printk("Failed to allocate IRQ %d\n", i);
return;
}
} }
} }
/* static void __init se7722_gc_init(void)
* Initialize IRQ setting
*/
void __init init_se7722_IRQ(void)
{ {
int i, irq; struct irq_chip_generic *gc;
struct irq_chip_type *ct;
unsigned int irq_base;
__raw_writew(0, IRQ01_MASK); /* disable all irqs */ irq_base = irq_linear_revmap(se7722_irq_domain, 0);
__raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */
for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) { gc = irq_alloc_generic_chip(DRV_NAME, 1, irq_base, se7722_irq_regs,
irq = create_irq(); handle_level_irq);
if (irq < 0) if (unlikely(!gc))
return; return;
se7722_fpga_irq[i] = irq;
irq_set_chip_and_handler_name(se7722_fpga_irq[i], ct = gc->chip_types;
&se7722_irq_chip, ct->chip.irq_mask = irq_gc_mask_set_bit;
handle_level_irq, ct->chip.irq_unmask = irq_gc_mask_clr_bit;
"level");
irq_set_chip_data(se7722_fpga_irq[i], (void *)i); ct->regs.mask = IRQ01_MASK_REG;
}
irq_setup_generic_chip(gc, IRQ_MSK(SE7722_FPGA_IRQ_NR),
IRQ_GC_INIT_MASK_CACHE,
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
irq_set_chained_handler(IRQ0_IRQ, se7722_irq_demux); irq_set_chained_handler(IRQ0_IRQ, se7722_irq_demux);
irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
...@@ -81,3 +98,25 @@ void __init init_se7722_IRQ(void) ...@@ -81,3 +98,25 @@ void __init init_se7722_IRQ(void)
irq_set_chained_handler(IRQ1_IRQ, se7722_irq_demux); irq_set_chained_handler(IRQ1_IRQ, se7722_irq_demux);
irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
} }
/*
* Initialize FPGA IRQs
*/
void __init init_se7722_IRQ(void)
{
se7722_irq_regs = ioremap(IRQ01_BASE_ADDR, SZ_16);
if (unlikely(!se7722_irq_regs)) {
printk("Failed to remap IRQ01 regs\n");
return;
}
/*
* All FPGA IRQs disabled by default
*/
iowrite16(0, se7722_irq_regs + IRQ01_MASK_REG);
__raw_writew(0x2000, 0xb03fffec); /* mrshpc irq enable */
se7722_domain_init();
se7722_gc_init();
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* linux/arch/sh/boards/se/7722/setup.c * linux/arch/sh/boards/se/7722/setup.c
* *
* Copyright (C) 2007 Nobuhiro Iwamatsu * Copyright (C) 2007 Nobuhiro Iwamatsu
* Copyright (C) 2012 Paul Mundt
* *
* Hitachi UL SolutionEngine 7722 Support. * Hitachi UL SolutionEngine 7722 Support.
* *
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include <linux/ata_platform.h> #include <linux/ata_platform.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/sh_keysc.h> #include <linux/input/sh_keysc.h>
#include <linux/irqdomain.h>
#include <linux/smc91x.h> #include <linux/smc91x.h>
#include <linux/sh_intc.h> #include <linux/sh_intc.h>
#include <mach-se/mach/se7722.h> #include <mach-se/mach/se7722.h>
...@@ -143,10 +145,10 @@ static int __init se7722_devices_setup(void) ...@@ -143,10 +145,10 @@ static int __init se7722_devices_setup(void)
/* Wire-up dynamic vectors */ /* Wire-up dynamic vectors */
cf_ide_resources[2].start = cf_ide_resources[2].end = cf_ide_resources[2].start = cf_ide_resources[2].end =
se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0]; irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_MRSHPC0);
smc91x_eth_resources[1].start = smc91x_eth_resources[1].end = smc91x_eth_resources[1].start = smc91x_eth_resources[1].end =
se7722_fpga_irq[SE7722_FPGA_IRQ_SMC]; irq_find_mapping(se7722_irq_domain, SE7722_FPGA_IRQ_SMC);
return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices)); return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices));
} }
......
...@@ -17,8 +17,10 @@ ...@@ -17,8 +17,10 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <asm/irq.h> #include <linux/export.h>
#include <asm/io.h> #include <linux/topology.h>
#include <linux/io.h>
#include <linux/err.h>
#include <mach-se/mach/se7724.h> #include <mach-se/mach/se7724.h>
struct fpga_irq { struct fpga_irq {
...@@ -111,7 +113,7 @@ static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc) ...@@ -111,7 +113,7 @@ static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
*/ */
void __init init_se7724_IRQ(void) void __init init_se7724_IRQ(void)
{ {
int i, nid = cpu_to_node(boot_cpu_data); int irq_base, i;
__raw_writew(0xffff, IRQ0_MR); /* mask all */ __raw_writew(0xffff, IRQ0_MR); /* mask all */
__raw_writew(0xffff, IRQ1_MR); /* mask all */ __raw_writew(0xffff, IRQ1_MR); /* mask all */
...@@ -121,28 +123,16 @@ void __init init_se7724_IRQ(void) ...@@ -121,28 +123,16 @@ void __init init_se7724_IRQ(void)
__raw_writew(0x0000, IRQ2_SR); /* clear irq */ __raw_writew(0x0000, IRQ2_SR); /* clear irq */
__raw_writew(0x002a, IRQ_MODE); /* set irq type */ __raw_writew(0x002a, IRQ_MODE); /* set irq type */
for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) { irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE,
int irq, wanted; SE7724_FPGA_IRQ_NR, numa_node_id());
if (IS_ERR_VALUE(irq_base)) {
wanted = SE7724_FPGA_IRQ_BASE + i; pr_err("%s: failed hooking irqs for FPGA\n", __func__);
return;
irq = create_irq_nr(wanted, nid); }
if (unlikely(irq == 0)) {
pr_err("%s: failed hooking irq %d for FPGA\n",
__func__, wanted);
return;
}
if (unlikely(irq != wanted)) {
pr_err("%s: got irq %d but wanted %d, bailing.\n",
__func__, irq, wanted);
destroy_irq(irq);
return;
}
irq_set_chip_and_handler_name(irq, &se7724_irq_chip, for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip,
handle_level_irq, "level"); handle_level_irq, "level");
}
irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux); irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* *
* Renesas SH-X3 Prototype Baseboard GPIO Support. * Renesas SH-X3 Prototype Baseboard GPIO Support.
* *
* Copyright (C) 2010 Paul Mundt * Copyright (C) 2010 - 2012 Paul Mundt
* *
* This file is subject to the terms and conditions of the GNU General Public * 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 * License. See the file "COPYING" in the main directory of this archive
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/irqdomain.h>
#include <linux/io.h> #include <linux/io.h>
#include <mach/ilsel.h> #include <mach/ilsel.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -26,7 +27,7 @@ ...@@ -26,7 +27,7 @@
#define KEYDETR 0xb81c0004 #define KEYDETR 0xb81c0004
static DEFINE_SPINLOCK(x3proto_gpio_lock); static DEFINE_SPINLOCK(x3proto_gpio_lock);
static unsigned int x3proto_gpio_irq_map[NR_BASEBOARD_GPIOS] = { 0, }; static struct irq_domain *x3proto_irq_domain;
static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) static int x3proto_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{ {
...@@ -49,7 +50,14 @@ static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio) ...@@ -49,7 +50,14 @@ static int x3proto_gpio_get(struct gpio_chip *chip, unsigned gpio)
static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) static int x3proto_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
{ {
return x3proto_gpio_irq_map[gpio]; int virq;
if (gpio < chip->ngpio)
virq = irq_create_mapping(x3proto_irq_domain, gpio);
else
virq = -ENXIO;
return virq;
} }
static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
...@@ -62,9 +70,8 @@ static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -62,9 +70,8 @@ static void x3proto_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
chip->irq_mask_ack(data); chip->irq_mask_ack(data);
mask = __raw_readw(KEYDETR); mask = __raw_readw(KEYDETR);
for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS) for_each_set_bit(pin, &mask, NR_BASEBOARD_GPIOS)
generic_handle_irq(x3proto_gpio_to_irq(NULL, pin)); generic_handle_irq(irq_linear_revmap(x3proto_irq_domain, pin));
chip->irq_unmask(data); chip->irq_unmask(data);
} }
...@@ -78,10 +85,23 @@ struct gpio_chip x3proto_gpio_chip = { ...@@ -78,10 +85,23 @@ struct gpio_chip x3proto_gpio_chip = {
.ngpio = NR_BASEBOARD_GPIOS, .ngpio = NR_BASEBOARD_GPIOS,
}; };
static int x3proto_gpio_irq_map(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
irq_set_chip_and_handler_name(virq, &dummy_irq_chip, handle_simple_irq,
"gpio");
return 0;
}
static struct irq_domain_ops x3proto_gpio_irq_ops = {
.map = x3proto_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
int __init x3proto_gpio_setup(void) int __init x3proto_gpio_setup(void)
{ {
int ilsel; int ilsel, ret;
int ret, i;
ilsel = ilsel_enable(ILSEL_KEY); ilsel = ilsel_enable(ILSEL_KEY);
if (unlikely(ilsel < 0)) if (unlikely(ilsel < 0))
...@@ -91,21 +111,10 @@ int __init x3proto_gpio_setup(void) ...@@ -91,21 +111,10 @@ int __init x3proto_gpio_setup(void)
if (unlikely(ret)) if (unlikely(ret))
goto err_gpio; goto err_gpio;
for (i = 0; i < NR_BASEBOARD_GPIOS; i++) { x3proto_irq_domain = irq_domain_add_linear(NULL, NR_BASEBOARD_GPIOS,
unsigned long flags; &x3proto_gpio_irq_ops, NULL);
int irq = create_irq(); if (unlikely(!x3proto_irq_domain))
goto err_irq;
if (unlikely(irq < 0)) {
ret = -EINVAL;
goto err_irq;
}
spin_lock_irqsave(&x3proto_gpio_lock, flags);
x3proto_gpio_irq_map[i] = irq;
irq_set_chip_and_handler_name(irq, &dummy_irq_chip,
handle_simple_irq, "gpio");
spin_unlock_irqrestore(&x3proto_gpio_lock, flags);
}
pr_info("registering '%s' support, handling GPIOs %u -> %u, " pr_info("registering '%s' support, handling GPIOs %u -> %u, "
"bound to IRQ %u\n", "bound to IRQ %u\n",
...@@ -119,10 +128,6 @@ int __init x3proto_gpio_setup(void) ...@@ -119,10 +128,6 @@ int __init x3proto_gpio_setup(void)
return 0; return 0;
err_irq: err_irq:
for (; i >= 0; --i)
if (x3proto_gpio_irq_map[i])
destroy_irq(x3proto_gpio_irq_map[i]);
ret = gpiochip_remove(&x3proto_gpio_chip); ret = gpiochip_remove(&x3proto_gpio_chip);
if (unlikely(ret)) if (unlikely(ret))
pr_err("Failed deregistering GPIO\n"); pr_err("Failed deregistering GPIO\n");
......
...@@ -73,10 +73,7 @@ static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc) ...@@ -73,10 +73,7 @@ static void hd64461_irq_demux(unsigned int irq, struct irq_desc *desc)
int __init setup_hd64461(void) int __init setup_hd64461(void)
{ {
int i, nid = cpu_to_node(boot_cpu_data); int irq_base, i;
if (!MACH_HD64461)
return 0;
printk(KERN_INFO printk(KERN_INFO
"HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n", "HD64461 configured at 0x%x on irq %d(mapped into %d to %d)\n",
...@@ -89,28 +86,16 @@ int __init setup_hd64461(void) ...@@ -89,28 +86,16 @@ int __init setup_hd64461(void)
#endif #endif
__raw_writew(0xffff, HD64461_NIMR); __raw_writew(0xffff, HD64461_NIMR);
/* IRQ 80 -> 95 belongs to HD64461 */ irq_base = irq_alloc_descs(HD64461_IRQBASE, HD64461_IRQBASE, 16, -1);
for (i = HD64461_IRQBASE; i < HD64461_IRQBASE + 16; i++) { if (IS_ERR_VALUE(irq_base)) {
unsigned int irq; pr_err("%s: failed hooking irqs for HD64461\n", __func__);
return irq_base;
irq = create_irq_nr(i, nid);
if (unlikely(irq == 0)) {
pr_err("%s: failed hooking irq %d for HD64461\n",
__func__, i);
return -EBUSY;
}
if (unlikely(irq != i)) {
pr_err("%s: got irq %d but wanted %d, bailing.\n",
__func__, irq, i);
destroy_irq(irq);
return -EINVAL;
}
irq_set_chip_and_handler(i, &hd64461_irq_chip,
handle_level_irq);
} }
for (i = 0; i < 16; i++)
irq_set_chip_and_handler(irq_base + i, &hd64461_irq_chip,
handle_level_irq);
irq_set_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux); irq_set_chained_handler(CONFIG_HD64461_IRQ, hd64461_irq_demux);
irq_set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW); irq_set_irq_type(CONFIG_HD64461_IRQ, IRQ_TYPE_LEVEL_LOW);
......
...@@ -110,6 +110,10 @@ do { \ ...@@ -110,6 +110,10 @@ do { \
#include <asm-generic/bug.h> #include <asm-generic/bug.h>
struct pt_regs; struct pt_regs;
/* arch/sh/kernel/traps.c */
extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn)); extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
extern void die_if_no_fixup(const char *str, struct pt_regs *regs, long err);
#endif /* __ASM_SH_BUG_H */ #endif /* __ASM_SH_BUG_H */
...@@ -10,6 +10,8 @@ enum die_val { ...@@ -10,6 +10,8 @@ enum die_val {
DIE_SSTEP, DIE_SSTEP,
}; };
/* arch/sh/kernel/dumpstack.c */
extern void printk_address(unsigned long address, int reliable); extern void printk_address(unsigned long address, int reliable);
extern void dump_mem(const char *str, unsigned long bottom, unsigned long top);
#endif /* __ASM_SH_KDEBUG_H */ #endif /* __ASM_SH_KDEBUG_H */
...@@ -50,9 +50,6 @@ ...@@ -50,9 +50,6 @@
#define PA_LED 0xb0C00000 /* LED */ #define PA_LED 0xb0C00000 /* LED */
#define LED_SHIFT 0 #define LED_SHIFT 0
#define PA_DIPSW 0xb0900000 /* Dip switch 31 */ #define PA_DIPSW 0xb0900000 /* Dip switch 31 */
#define PA_CPLD_MODESET 0xb1400004 /* CPLD Mode set register */
#define PA_CPLD_ST 0xb1400008 /* CPLD Interrupt status register */
#define PA_CPLD_IMSK 0xb140000a /* CPLD Interrupt mask register */
/* Area 5 */ /* Area 5 */
#define PA_EXT5 0x14000000 #define PA_EXT5 0x14000000
#define PA_EXT5_SIZE 0x04000000 #define PA_EXT5_SIZE 0x04000000
...@@ -135,8 +132,10 @@ ...@@ -135,8 +132,10 @@
#define SE7343_FPGA_IRQ_NR 12 #define SE7343_FPGA_IRQ_NR 12
struct irq_domain;
/* arch/sh/boards/se/7343/irq.c */ /* arch/sh/boards/se/7343/irq.c */
extern unsigned int se7343_fpga_irq[]; extern struct irq_domain *se7343_irq_domain;
void init_7343se_IRQ(void); void init_7343se_IRQ(void);
......
...@@ -81,12 +81,6 @@ ...@@ -81,12 +81,6 @@
#define IRQ0_IRQ evt2irq(0x600) #define IRQ0_IRQ evt2irq(0x600)
#define IRQ1_IRQ evt2irq(0x620) #define IRQ1_IRQ evt2irq(0x620)
#define IRQ01_MODE 0xb1800000
#define IRQ01_STS 0xb1800004
#define IRQ01_MASK 0xb1800008
/* Bits in IRQ01_* registers */
#define SE7722_FPGA_IRQ_USB 0 /* IRQ0 */ #define SE7722_FPGA_IRQ_USB 0 /* IRQ0 */
#define SE7722_FPGA_IRQ_SMC 1 /* IRQ0 */ #define SE7722_FPGA_IRQ_SMC 1 /* IRQ0 */
#define SE7722_FPGA_IRQ_MRSHPC0 2 /* IRQ1 */ #define SE7722_FPGA_IRQ_MRSHPC0 2 /* IRQ1 */
...@@ -95,8 +89,10 @@ ...@@ -95,8 +89,10 @@
#define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */ #define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */
#define SE7722_FPGA_IRQ_NR 6 #define SE7722_FPGA_IRQ_NR 6
struct irq_domain;
/* arch/sh/boards/se/7722/irq.c */ /* arch/sh/boards/se/7722/irq.c */
extern unsigned int se7722_fpga_irq[]; extern struct irq_domain *se7722_irq_domain;
void init_se7722_IRQ(void); void init_se7722_IRQ(void);
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/unwinder.h>
#include <asm/stacktrace.h>
static u8 regcache[63]; static u8 regcache[63];
...@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc, ...@@ -199,8 +201,11 @@ static int lookup_prev_stack_frame(unsigned long fp, unsigned long pc,
return 0; return 0;
} }
/* Don't put this on the stack since we'll want to call sh64_unwind /*
* when we're close to underflowing the stack anyway. */ * Don't put this on the stack since we'll want to call in to
* sh64_unwinder_dump() when we're close to underflowing the stack
* anyway.
*/
static struct pt_regs here_regs; static struct pt_regs here_regs;
extern const char syscall_ret; extern const char syscall_ret;
...@@ -208,17 +213,19 @@ extern const char ret_from_syscall; ...@@ -208,17 +213,19 @@ extern const char ret_from_syscall;
extern const char ret_from_exception; extern const char ret_from_exception;
extern const char ret_from_irq; extern const char ret_from_irq;
static void sh64_unwind_inner(struct pt_regs *regs); static void sh64_unwind_inner(const struct stacktrace_ops *ops,
void *data, struct pt_regs *regs);
static void unwind_nested (unsigned long pc, unsigned long fp) static inline void unwind_nested(const struct stacktrace_ops *ops, void *data,
unsigned long pc, unsigned long fp)
{ {
if ((fp >= __MEMORY_START) && if ((fp >= __MEMORY_START) &&
((fp & 7) == 0)) { ((fp & 7) == 0))
sh64_unwind_inner((struct pt_regs *) fp); sh64_unwind_inner(ops, data, (struct pt_regs *)fp);
}
} }
static void sh64_unwind_inner(struct pt_regs *regs) static void sh64_unwind_inner(const struct stacktrace_ops *ops,
void *data, struct pt_regs *regs)
{ {
unsigned long pc, fp; unsigned long pc, fp;
int ofs = 0; int ofs = 0;
...@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs) ...@@ -232,29 +239,29 @@ static void sh64_unwind_inner(struct pt_regs *regs)
int cond; int cond;
unsigned long next_fp, next_pc; unsigned long next_fp, next_pc;
if (pc == ((unsigned long) &syscall_ret & ~1)) { if (pc == ((unsigned long)&syscall_ret & ~1)) {
printk("SYSCALL\n"); printk("SYSCALL\n");
unwind_nested(pc,fp); unwind_nested(ops, data, pc, fp);
return; return;
} }
if (pc == ((unsigned long) &ret_from_syscall & ~1)) { if (pc == ((unsigned long)&ret_from_syscall & ~1)) {
printk("SYSCALL (PREEMPTED)\n"); printk("SYSCALL (PREEMPTED)\n");
unwind_nested(pc,fp); unwind_nested(ops, data, pc, fp);
return; return;
} }
/* In this case, the PC is discovered by lookup_prev_stack_frame but /* In this case, the PC is discovered by lookup_prev_stack_frame but
it has 4 taken off it to look like the 'caller' */ it has 4 taken off it to look like the 'caller' */
if (pc == ((unsigned long) &ret_from_exception & ~1)) { if (pc == ((unsigned long)&ret_from_exception & ~1)) {
printk("EXCEPTION\n"); printk("EXCEPTION\n");
unwind_nested(pc,fp); unwind_nested(ops, data, pc, fp);
return; return;
} }
if (pc == ((unsigned long) &ret_from_irq & ~1)) { if (pc == ((unsigned long)&ret_from_irq & ~1)) {
printk("IRQ\n"); printk("IRQ\n");
unwind_nested(pc,fp); unwind_nested(ops, data, pc, fp);
return; return;
} }
...@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs) ...@@ -263,8 +270,7 @@ static void sh64_unwind_inner(struct pt_regs *regs)
pc -= ofs; pc -= ofs;
printk("[<%08lx>] ", pc); ops->address(data, pc, 1);
print_symbol("%s\n", pc);
if (first_pass) { if (first_pass) {
/* If the innermost frame is a leaf function, it's /* If the innermost frame is a leaf function, it's
...@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs) ...@@ -287,10 +293,13 @@ static void sh64_unwind_inner(struct pt_regs *regs)
} }
printk("\n"); printk("\n");
} }
void sh64_unwind(struct pt_regs *regs) static void sh64_unwinder_dump(struct task_struct *task,
struct pt_regs *regs,
unsigned long *sp,
const struct stacktrace_ops *ops,
void *data)
{ {
if (!regs) { if (!regs) {
/* /*
...@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs) ...@@ -320,7 +329,17 @@ void sh64_unwind(struct pt_regs *regs)
); );
} }
printk("\nCall Trace:\n"); sh64_unwind_inner(ops, data, regs);
sh64_unwind_inner(regs);
} }
static struct unwinder sh64_unwinder = {
.name = "sh64-unwinder",
.dump = sh64_unwinder_dump,
.rating = 150,
};
static int __init sh64_unwinder_init(void)
{
return unwinder_register(&sh64_unwinder);
}
early_initcall(sh64_unwinder_init);
...@@ -2,13 +2,48 @@ ...@@ -2,13 +2,48 @@
* Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs
* Copyright (C) 2009 Matt Fleming * Copyright (C) 2009 Matt Fleming
* Copyright (C) 2002 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/ */
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <linux/debug_locks.h> #include <linux/debug_locks.h>
#include <linux/kdebug.h>
#include <linux/export.h>
#include <linux/uaccess.h>
#include <asm/unwinder.h> #include <asm/unwinder.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
void dump_mem(const char *str, unsigned long bottom, unsigned long top)
{
unsigned long p;
int i;
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
for (p = bottom & ~31; p < top; ) {
printk("%04lx: ", p & 0xffff);
for (i = 0; i < 8; i++, p += 4) {
unsigned int val;
if (p < bottom || p >= top)
printk(" ");
else {
if (__get_user(val, (unsigned int __user *)p)) {
printk("\n");
return;
}
printk("%08x ", val);
}
}
printk("\n");
}
}
void printk_address(unsigned long address, int reliable) void printk_address(unsigned long address, int reliable)
{ {
printk(" [<%p>] %s%pS\n", (void *) address, printk(" [<%p>] %s%pS\n", (void *) address,
...@@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp, ...@@ -106,3 +141,26 @@ void show_trace(struct task_struct *tsk, unsigned long *sp,
debug_show_held_locks(tsk); debug_show_held_locks(tsk);
} }
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
unsigned long stack;
if (!tsk)
tsk = current;
if (tsk == current)
sp = (unsigned long *)current_stack_pointer;
else
sp = (unsigned long *)tsk->thread.sp;
stack = (unsigned long)sp;
dump_mem("Stack: ", stack, THREAD_SIZE +
(unsigned long)task_stack_page(tsk));
show_trace(tsk, sp, NULL);
}
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
...@@ -231,16 +231,6 @@ void __init init_IRQ(void) ...@@ -231,16 +231,6 @@ void __init init_IRQ(void)
irq_ctx_init(smp_processor_id()); irq_ctx_init(smp_processor_id());
} }
#ifdef CONFIG_SPARSE_IRQ
int __init arch_probe_nr_irqs(void)
{
/*
* No pre-allocated IRQs.
*/
return 0;
}
#endif
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu) static void route_irq(struct irq_data *data, unsigned int irq, unsigned int cpu)
{ {
......
...@@ -6,9 +6,80 @@ ...@@ -6,9 +6,80 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/module.h>
#include <asm/unwinder.h> #include <asm/unwinder.h>
#include <asm/traps.h> #include <asm/traps.h>
static DEFINE_SPINLOCK(die_lock);
void die(const char *str, struct pt_regs *regs, long err)
{
static int die_counter;
oops_enter();
spin_lock_irq(&die_lock);
console_verbose();
bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
print_modules();
show_regs(regs);
printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
task_pid_nr(current), task_stack_page(current) + 1);
if (!user_mode(regs) || in_interrupt())
dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
(unsigned long)task_stack_page(current));
notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
bust_spinlocks(0);
add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
oops_exit();
if (kexec_should_crash(current))
crash_kexec(regs);
if (in_interrupt())
panic("Fatal exception in interrupt");
if (panic_on_oops)
panic("Fatal exception");
do_exit(SIGSEGV);
}
void die_if_kernel(const char *str, struct pt_regs *regs, long err)
{
if (!user_mode(regs))
die(str, regs, err);
}
/*
* try and fix up kernelspace address errors
* - userspace errors just cause EFAULT to be returned, resulting in SEGV
* - kernel/userspace interfaces cause a jump to an appropriate handler
* - other kernel errors are bad
*/
void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
{
if (!user_mode(regs)) {
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->pc);
if (fixup) {
regs->pc = fixup->fixup;
return;
}
die(str, regs, err);
}
}
#ifdef CONFIG_GENERIC_BUG #ifdef CONFIG_GENERIC_BUG
static void handle_BUG(struct pt_regs *regs) static void handle_BUG(struct pt_regs *regs)
{ {
......
...@@ -16,13 +16,11 @@ ...@@ -16,13 +16,11 @@
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/bug.h> #include <linux/bug.h>
#include <linux/debug_locks.h> #include <linux/debug_locks.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
#include <linux/kexec.h>
#include <linux/limits.h> #include <linux/limits.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -48,102 +46,6 @@ ...@@ -48,102 +46,6 @@
#define TRAP_ILLEGAL_SLOT_INST 13 #define TRAP_ILLEGAL_SLOT_INST 13
#endif #endif
static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
{
unsigned long p;
int i;
printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
for (p = bottom & ~31; p < top; ) {
printk("%04lx: ", p & 0xffff);
for (i = 0; i < 8; i++, p += 4) {
unsigned int val;
if (p < bottom || p >= top)
printk(" ");
else {
if (__get_user(val, (unsigned int __user *)p)) {
printk("\n");
return;
}
printk("%08x ", val);
}
}
printk("\n");
}
}
static DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
static int die_counter;
oops_enter();
spin_lock_irq(&die_lock);
console_verbose();
bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
print_modules();
show_regs(regs);
printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
task_pid_nr(current), task_stack_page(current) + 1);
if (!user_mode(regs) || in_interrupt())
dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
(unsigned long)task_stack_page(current));
notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
bust_spinlocks(0);
add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
oops_exit();
if (kexec_should_crash(current))
crash_kexec(regs);
if (in_interrupt())
panic("Fatal exception in interrupt");
if (panic_on_oops)
panic("Fatal exception");
do_exit(SIGSEGV);
}
static inline void die_if_kernel(const char *str, struct pt_regs *regs,
long err)
{
if (!user_mode(regs))
die(str, regs, err);
}
/*
* try and fix up kernelspace address errors
* - userspace errors just cause EFAULT to be returned, resulting in SEGV
* - kernel/userspace interfaces cause a jump to an appropriate handler
* - other kernel errors are bad
*/
static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
{
if (!user_mode(regs)) {
const struct exception_table_entry *fixup;
fixup = search_exception_tables(regs->pc);
if (fixup) {
regs->pc = fixup->fixup;
return;
}
die(str, regs, err);
}
}
static inline void sign_extend(unsigned int count, unsigned char *dst) static inline void sign_extend(unsigned int count, unsigned char *dst)
{ {
#ifdef __LITTLE_ENDIAN__ #ifdef __LITTLE_ENDIAN__
...@@ -900,26 +802,3 @@ void __init trap_init(void) ...@@ -900,26 +802,3 @@ void __init trap_init(void)
set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler); set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
#endif #endif
} }
void show_stack(struct task_struct *tsk, unsigned long *sp)
{
unsigned long stack;
if (!tsk)
tsk = current;
if (tsk == current)
sp = (unsigned long *)current_stack_pointer;
else
sp = (unsigned long *)tsk->thread.sp;
stack = (unsigned long)sp;
dump_mem("Stack: ", stack, THREAD_SIZE +
(unsigned long)task_stack_page(tsk));
show_trace(tsk, sp, NULL);
}
void dump_stack(void)
{
show_stack(NULL, NULL);
}
EXPORT_SYMBOL(dump_stack);
This diff is collapsed.
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# Panic should really be compiled as PIC # Panic should really be compiled as PIC
lib-y := udelay.o dbg.o panic.o memcpy.o memset.o \ lib-y := udelay.o panic.o memcpy.o memset.o \
copy_user_memcpy.o copy_page.o strcpy.o strlen.o copy_user_memcpy.o copy_page.o strcpy.o strlen.o
# Extracted from libgcc # Extracted from libgcc
......
/*--------------------------------------------------------------------------
--
-- Identity : Linux50 Debug Funcions
--
-- File : arch/sh/lib64/dbg.c
--
-- Copyright 2000, 2001 STMicroelectronics Limited.
-- Copyright 2004 Richard Curnow (evt_debug etc)
--
--------------------------------------------------------------------------*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <asm/mmu_context.h>
typedef u64 regType_t;
static regType_t getConfigReg(u64 id)
{
register u64 reg __asm__("r2");
asm volatile ("getcfg %1, 0, %0":"=r" (reg):"r"(id));
return (reg);
}
/* ======================================================================= */
static char *szTab[] = { "4k", "64k", "1M", "512M" };
static char *protTab[] = { "----",
"---R",
"--X-",
"--XR",
"-W--",
"-W-R",
"-WX-",
"-WXR",
"U---",
"U--R",
"U-X-",
"U-XR",
"UW--",
"UW-R",
"UWX-",
"UWXR"
};
#define ITLB_BASE 0x00000000
#define DTLB_BASE 0x00800000
#define MAX_TLBs 64
/* PTE High */
#define GET_VALID(pte) ((pte) & 0x1)
#define GET_SHARED(pte) ((pte) & 0x2)
#define GET_ASID(pte) ((pte >> 2) & 0x0ff)
#define GET_EPN(pte) ((pte) & 0xfffff000)
/* PTE Low */
#define GET_CBEHAVIOR(pte) ((pte) & 0x3)
#define GET_PAGE_SIZE(pte) szTab[((pte >> 3) & 0x3)]
#define GET_PROTECTION(pte) protTab[((pte >> 6) & 0xf)]
#define GET_PPN(pte) ((pte) & 0xfffff000)
#define PAGE_1K_MASK 0x00000000
#define PAGE_4K_MASK 0x00000010
#define PAGE_64K_MASK 0x00000080
#define MMU_PAGESIZE_MASK (PAGE_64K_MASK | PAGE_4K_MASK)
#define PAGE_1MB_MASK MMU_PAGESIZE_MASK
#define PAGE_1K (1024)
#define PAGE_4K (1024 * 4)
#define PAGE_64K (1024 * 64)
#define PAGE_1MB (1024 * 1024)
#define HOW_TO_READ_TLB_CONTENT \
"[ ID] PPN EPN ASID Share CB P.Size PROT.\n"
void print_single_tlb(unsigned long tlb, int single_print)
{
regType_t pteH;
regType_t pteL;
unsigned int valid, shared, asid, epn, cb, ppn;
char *pSize;
char *pProt;
/*
** in case of single print <single_print> is true, this implies:
** 1) print the TLB in any case also if NOT VALID
** 2) print out the header
*/
pteH = getConfigReg(tlb);
valid = GET_VALID(pteH);
if (single_print)
printk(HOW_TO_READ_TLB_CONTENT);
else if (!valid)
return;
pteL = getConfigReg(tlb + 1);
shared = GET_SHARED(pteH);
asid = GET_ASID(pteH);
epn = GET_EPN(pteH);
cb = GET_CBEHAVIOR(pteL);
pSize = GET_PAGE_SIZE(pteL);
pProt = GET_PROTECTION(pteL);
ppn = GET_PPN(pteL);
printk("[%c%2ld] 0x%08x 0x%08x %03d %02x %02x %4s %s\n",
((valid) ? ' ' : 'u'), ((tlb & 0x0ffff) / TLB_STEP),
ppn, epn, asid, shared, cb, pSize, pProt);
}
void print_dtlb(void)
{
int count;
unsigned long tlb;
printk(" ================= SH-5 D-TLBs Status ===================\n");
printk(HOW_TO_READ_TLB_CONTENT);
tlb = DTLB_BASE;
for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
print_single_tlb(tlb, 0);
printk
(" =============================================================\n");
}
void print_itlb(void)
{
int count;
unsigned long tlb;
printk(" ================= SH-5 I-TLBs Status ===================\n");
printk(HOW_TO_READ_TLB_CONTENT);
tlb = ITLB_BASE;
for (count = 0; count < MAX_TLBs; count++, tlb += TLB_STEP)
print_single_tlb(tlb, 0);
printk
(" =============================================================\n");
}
void show_excp_regs(char *from, int trapnr, int signr, struct pt_regs *regs)
{
unsigned long long ah, al, bh, bl, ch, cl;
printk("\n");
printk("EXCEPTION - %s: task %d; Linux trap # %d; signal = %d\n",
((from) ? from : "???"), current->pid, trapnr, signr);
asm volatile ("getcon " __EXPEVT ", %0":"=r"(ah));
asm volatile ("getcon " __EXPEVT ", %0":"=r"(al));
ah = (ah) >> 32;
al = (al) & 0xffffffff;
asm volatile ("getcon " __KCR1 ", %0":"=r"(bh));
asm volatile ("getcon " __KCR1 ", %0":"=r"(bl));
bh = (bh) >> 32;
bl = (bl) & 0xffffffff;
asm volatile ("getcon " __INTEVT ", %0":"=r"(ch));
asm volatile ("getcon " __INTEVT ", %0":"=r"(cl));
ch = (ch) >> 32;
cl = (cl) & 0xffffffff;
printk("EXPE: %08Lx%08Lx KCR1: %08Lx%08Lx INTE: %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
asm volatile ("getcon " __PEXPEVT ", %0":"=r"(ah));
asm volatile ("getcon " __PEXPEVT ", %0":"=r"(al));
ah = (ah) >> 32;
al = (al) & 0xffffffff;
asm volatile ("getcon " __PSPC ", %0":"=r"(bh));
asm volatile ("getcon " __PSPC ", %0":"=r"(bl));
bh = (bh) >> 32;
bl = (bl) & 0xffffffff;
asm volatile ("getcon " __PSSR ", %0":"=r"(ch));
asm volatile ("getcon " __PSSR ", %0":"=r"(cl));
ch = (ch) >> 32;
cl = (cl) & 0xffffffff;
printk("PEXP: %08Lx%08Lx PSPC: %08Lx%08Lx PSSR: %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->pc) >> 32;
al = (regs->pc) & 0xffffffff;
bh = (regs->regs[18]) >> 32;
bl = (regs->regs[18]) & 0xffffffff;
ch = (regs->regs[15]) >> 32;
cl = (regs->regs[15]) & 0xffffffff;
printk("PC : %08Lx%08Lx LINK: %08Lx%08Lx SP : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->sr) >> 32;
al = (regs->sr) & 0xffffffff;
asm volatile ("getcon " __TEA ", %0":"=r"(bh));
asm volatile ("getcon " __TEA ", %0":"=r"(bl));
bh = (bh) >> 32;
bl = (bl) & 0xffffffff;
asm volatile ("getcon " __KCR0 ", %0":"=r"(ch));
asm volatile ("getcon " __KCR0 ", %0":"=r"(cl));
ch = (ch) >> 32;
cl = (cl) & 0xffffffff;
printk("SR : %08Lx%08Lx TEA : %08Lx%08Lx KCR0: %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->regs[0]) >> 32;
al = (regs->regs[0]) & 0xffffffff;
bh = (regs->regs[1]) >> 32;
bl = (regs->regs[1]) & 0xffffffff;
ch = (regs->regs[2]) >> 32;
cl = (regs->regs[2]) & 0xffffffff;
printk("R0 : %08Lx%08Lx R1 : %08Lx%08Lx R2 : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->regs[3]) >> 32;
al = (regs->regs[3]) & 0xffffffff;
bh = (regs->regs[4]) >> 32;
bl = (regs->regs[4]) & 0xffffffff;
ch = (regs->regs[5]) >> 32;
cl = (regs->regs[5]) & 0xffffffff;
printk("R3 : %08Lx%08Lx R4 : %08Lx%08Lx R5 : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->regs[6]) >> 32;
al = (regs->regs[6]) & 0xffffffff;
bh = (regs->regs[7]) >> 32;
bl = (regs->regs[7]) & 0xffffffff;
ch = (regs->regs[8]) >> 32;
cl = (regs->regs[8]) & 0xffffffff;
printk("R6 : %08Lx%08Lx R7 : %08Lx%08Lx R8 : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
ah = (regs->regs[9]) >> 32;
al = (regs->regs[9]) & 0xffffffff;
bh = (regs->regs[10]) >> 32;
bl = (regs->regs[10]) & 0xffffffff;
ch = (regs->regs[11]) >> 32;
cl = (regs->regs[11]) & 0xffffffff;
printk("R9 : %08Lx%08Lx R10 : %08Lx%08Lx R11 : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
printk("....\n");
ah = (regs->tregs[0]) >> 32;
al = (regs->tregs[0]) & 0xffffffff;
bh = (regs->tregs[1]) >> 32;
bl = (regs->tregs[1]) & 0xffffffff;
ch = (regs->tregs[2]) >> 32;
cl = (regs->tregs[2]) & 0xffffffff;
printk("T0 : %08Lx%08Lx T1 : %08Lx%08Lx T2 : %08Lx%08Lx\n",
ah, al, bh, bl, ch, cl);
printk("....\n");
print_dtlb();
print_itlb();
}
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
/** /**
* sh64_tlb_init - Perform initial setup for the DTLB and ITLB. * sh64_tlb_init - Perform initial setup for the DTLB and ITLB.
*/ */
int __init sh64_tlb_init(void) int __cpuinit sh64_tlb_init(void)
{ {
/* Assign some sane DTLB defaults */ /* Assign some sane DTLB defaults */
cpu_data->dtlb.entries = 64; cpu_data->dtlb.entries = 64;
......
menu "SuperH / SH-Mobile Driver Options" menu "SuperH / SH-Mobile Driver Options"
source "drivers/sh/intc/Kconfig" source "drivers/sh/intc/Kconfig"
source "drivers/sh/pfc/Kconfig"
endmenu endmenu
...@@ -5,6 +5,7 @@ obj-y := intc/ ...@@ -5,6 +5,7 @@ obj-y := intc/
obj-$(CONFIG_HAVE_CLK) += clk/ obj-$(CONFIG_HAVE_CLK) += clk/
obj-$(CONFIG_MAPLE) += maple/ obj-$(CONFIG_MAPLE) += maple/
obj-$(CONFIG_SH_PFC) += pfc/
obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_GENERIC_GPIO) += pfc.o
obj-y += pm_runtime.o obj-y += pm_runtime.o
This diff is collapsed.
obj-y := access.o chip.o core.o dynamic.o handle.o virq.o obj-y := access.o chip.o core.o handle.o virq.o
obj-$(CONFIG_INTC_BALANCING) += balancing.o obj-$(CONFIG_INTC_BALANCING) += balancing.o
obj-$(CONFIG_INTC_USERIMASK) += userimask.o obj-$(CONFIG_INTC_USERIMASK) += userimask.o
......
/*
* Dynamic IRQ management
*
* Copyright (C) 2010 Paul Mundt
*
* Modelled after arch/x86/kernel/apic/io_apic.c
*
* 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.
*/
#define pr_fmt(fmt) "intc: " fmt
#include <linux/irq.h>
#include <linux/bitmap.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include "internals.h" /* only for activate_irq() damage.. */
/*
* The IRQ bitmap provides a global map of bound IRQ vectors for a
* given platform. Allocation of IRQs are either static through the CPU
* vector map, or dynamic in the case of board mux vectors or MSI.
*
* As this is a central point for all IRQ controllers on the system,
* each of the available sources are mapped out here. This combined with
* sparseirq makes it quite trivial to keep the vector map tightly packed
* when dynamically creating IRQs, as well as tying in to otherwise
* unused irq_desc positions in the sparse array.
*/
/*
* Dynamic IRQ allocation and deallocation
*/
unsigned int create_irq_nr(unsigned int irq_want, int node)
{
int irq = irq_alloc_desc_at(irq_want, node);
if (irq < 0)
return 0;
activate_irq(irq);
return irq;
}
int create_irq(void)
{
int irq = irq_alloc_desc(numa_node_id());
if (irq >= 0)
activate_irq(irq);
return irq;
}
void destroy_irq(unsigned int irq)
{
irq_free_desc(irq);
}
...@@ -219,12 +219,14 @@ static void __init intc_subgroup_map(struct intc_desc_int *d) ...@@ -219,12 +219,14 @@ static void __init intc_subgroup_map(struct intc_desc_int *d)
if (radix_tree_deref_retry(entry)) if (radix_tree_deref_retry(entry))
goto restart; goto restart;
irq = create_irq(); irq = irq_alloc_desc(numa_node_id());
if (unlikely(irq < 0)) { if (unlikely(irq < 0)) {
pr_err("no more free IRQs, bailing..\n"); pr_err("no more free IRQs, bailing..\n");
break; break;
} }
activate_irq(irq);
pr_info("Setting up a chained VIRQ from %d -> %d\n", pr_info("Setting up a chained VIRQ from %d -> %d\n",
irq, entry->pirq); irq, entry->pirq);
......
comment "Pin function controller options"
config SH_PFC
# XXX move off the gpio dependency
depends on GENERIC_GPIO
select GPIO_SH_PFC if ARCH_REQUIRE_GPIOLIB
select PINCTRL_SH_PFC
def_bool y
#
# Placeholder for now, rehome to drivers/pinctrl once the PFC APIs
# have settled.
#
config PINCTRL_SH_PFC
tristate "SuperH PFC pin controller driver"
depends on SH_PFC
select PINCTRL
select PINMUX
select PINCONF
config GPIO_SH_PFC
tristate "SuperH PFC GPIO support"
depends on SH_PFC && GPIOLIB
help
This enables support for GPIOs within the SoC's pin function
controller.
obj-y += core.o
obj-$(CONFIG_PINCTRL_SH_PFC) += pinctrl.o
obj-$(CONFIG_GPIO_SH_PFC) += gpio.o
This diff is collapsed.
/*
* SuperH Pin Function Controller GPIO driver.
*
* Copyright (C) 2008 Magnus Damm
* Copyright (C) 2009 - 2012 Paul Mundt
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#define pr_fmt(fmt) "sh_pfc " KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/consumer.h>
struct sh_pfc_chip {
struct sh_pfc *pfc;
struct gpio_chip gpio_chip;
};
static struct sh_pfc_chip *gpio_to_pfc_chip(struct gpio_chip *gc)
{
return container_of(gc, struct sh_pfc_chip, gpio_chip);
}
static struct sh_pfc *gpio_to_pfc(struct gpio_chip *gc)
{
return gpio_to_pfc_chip(gc)->pfc;
}
static int sh_gpio_request(struct gpio_chip *gc, unsigned offset)
{
return pinctrl_request_gpio(offset);
}
static void sh_gpio_free(struct gpio_chip *gc, unsigned offset)
{
pinctrl_free_gpio(offset);
}
static void sh_gpio_set_value(struct sh_pfc *pfc, unsigned gpio, int value)
{
struct pinmux_data_reg *dr = NULL;
int bit = 0;
if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
BUG();
else
sh_pfc_write_bit(dr, bit, value);
}
static int sh_gpio_get_value(struct sh_pfc *pfc, unsigned gpio)
{
struct pinmux_data_reg *dr = NULL;
int bit = 0;
if (!pfc || sh_pfc_get_data_reg(pfc, gpio, &dr, &bit) != 0)
return -EINVAL;
return sh_pfc_read_bit(dr, bit);
}
static int sh_gpio_direction_input(struct gpio_chip *gc, unsigned offset)
{
return pinctrl_gpio_direction_input(offset);
}
static int sh_gpio_direction_output(struct gpio_chip *gc, unsigned offset,
int value)
{
sh_gpio_set_value(gpio_to_pfc(gc), offset, value);
return pinctrl_gpio_direction_output(offset);
}
static int sh_gpio_get(struct gpio_chip *gc, unsigned offset)
{
return sh_gpio_get_value(gpio_to_pfc(gc), offset);
}
static void sh_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
sh_gpio_set_value(gpio_to_pfc(gc), offset, value);
}
static int sh_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct sh_pfc *pfc = gpio_to_pfc(gc);
pinmux_enum_t enum_id;
pinmux_enum_t *enum_ids;
int i, k, pos;
pos = 0;
enum_id = 0;
while (1) {
pos = sh_pfc_gpio_to_enum(pfc, offset, pos, &enum_id);
if (pos <= 0 || !enum_id)
break;
for (i = 0; i < pfc->gpio_irq_size; i++) {
enum_ids = pfc->gpio_irq[i].enum_ids;
for (k = 0; enum_ids[k]; k++) {
if (enum_ids[k] == enum_id)
return pfc->gpio_irq[i].irq;
}
}
}
return -ENOSYS;
}
static void sh_pfc_gpio_setup(struct sh_pfc_chip *chip)
{
struct sh_pfc *pfc = chip->pfc;
struct gpio_chip *gc = &chip->gpio_chip;
gc->request = sh_gpio_request;
gc->free = sh_gpio_free;
gc->direction_input = sh_gpio_direction_input;
gc->get = sh_gpio_get;
gc->direction_output = sh_gpio_direction_output;
gc->set = sh_gpio_set;
gc->to_irq = sh_gpio_to_irq;
WARN_ON(pfc->first_gpio != 0); /* needs testing */
gc->label = pfc->name;
gc->owner = THIS_MODULE;
gc->base = pfc->first_gpio;
gc->ngpio = (pfc->last_gpio - pfc->first_gpio) + 1;
}
int sh_pfc_register_gpiochip(struct sh_pfc *pfc)
{
struct sh_pfc_chip *chip;
int ret;
chip = kzalloc(sizeof(struct sh_pfc_chip), GFP_KERNEL);
if (unlikely(!chip))
return -ENOMEM;
chip->pfc = pfc;
sh_pfc_gpio_setup(chip);
ret = gpiochip_add(&chip->gpio_chip);
if (unlikely(ret < 0))
kfree(chip);
pr_info("%s handling gpio %d -> %d\n",
pfc->name, pfc->first_gpio, pfc->last_gpio);
return ret;
}
EXPORT_SYMBOL_GPL(sh_pfc_register_gpiochip);
static int sh_pfc_gpio_match(struct gpio_chip *gc, void *data)
{
return !!strstr(gc->label, data);
}
static int __devinit sh_pfc_gpio_probe(struct platform_device *pdev)
{
struct sh_pfc_chip *chip;
struct gpio_chip *gc;
gc = gpiochip_find("_pfc", sh_pfc_gpio_match);
if (unlikely(!gc)) {
pr_err("Cant find gpio chip\n");
return -ENODEV;
}
chip = gpio_to_pfc_chip(gc);
platform_set_drvdata(pdev, chip);
pr_info("attaching to GPIO chip %s\n", chip->pfc->name);
return 0;
}
static int __devexit sh_pfc_gpio_remove(struct platform_device *pdev)
{
struct sh_pfc_chip *chip = platform_get_drvdata(pdev);
int ret;
ret = gpiochip_remove(&chip->gpio_chip);
if (unlikely(ret < 0))
return ret;
kfree(chip);
return 0;
}
static struct platform_driver sh_pfc_gpio_driver = {
.probe = sh_pfc_gpio_probe,
.remove = __devexit_p(sh_pfc_gpio_remove),
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
},
};
static struct platform_device sh_pfc_gpio_device = {
.name = KBUILD_MODNAME,
.id = -1,
};
static int __init sh_pfc_gpio_init(void)
{
int rc;
rc = platform_driver_register(&sh_pfc_gpio_driver);
if (likely(!rc)) {
rc = platform_device_register(&sh_pfc_gpio_device);
if (unlikely(rc))
platform_driver_unregister(&sh_pfc_gpio_driver);
}
return rc;
}
static void __exit sh_pfc_gpio_exit(void)
{
platform_device_unregister(&sh_pfc_gpio_device);
platform_driver_unregister(&sh_pfc_gpio_driver);
}
module_init(sh_pfc_gpio_init);
module_exit(sh_pfc_gpio_exit);
MODULE_AUTHOR("Magnus Damm, Paul Mundt");
MODULE_DESCRIPTION("GPIO driver for SuperH pin function controller");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:pfc-gpio");
This diff is collapsed.
...@@ -18,7 +18,6 @@ struct clk_mapping { ...@@ -18,7 +18,6 @@ struct clk_mapping {
struct kref ref; struct kref ref;
}; };
struct sh_clk_ops { struct sh_clk_ops {
#ifdef CONFIG_SH_CLK_CPG_LEGACY #ifdef CONFIG_SH_CLK_CPG_LEGACY
void (*init)(struct clk *clk); void (*init)(struct clk *clk);
...@@ -31,6 +30,10 @@ struct sh_clk_ops { ...@@ -31,6 +30,10 @@ struct sh_clk_ops {
long (*round_rate)(struct clk *clk, unsigned long rate); long (*round_rate)(struct clk *clk, unsigned long rate);
}; };
#define SH_CLK_DIV_MSK(div) ((1 << (div)) - 1)
#define SH_CLK_DIV4_MSK SH_CLK_DIV_MSK(4)
#define SH_CLK_DIV6_MSK SH_CLK_DIV_MSK(6)
struct clk { struct clk {
struct list_head node; struct list_head node;
struct clk *parent; struct clk *parent;
...@@ -52,6 +55,7 @@ struct clk { ...@@ -52,6 +55,7 @@ struct clk {
unsigned int enable_bit; unsigned int enable_bit;
void __iomem *mapped_reg; void __iomem *mapped_reg;
unsigned int div_mask;
unsigned long arch_flags; unsigned long arch_flags;
void *priv; void *priv;
struct clk_mapping *mapping; struct clk_mapping *mapping;
...@@ -65,6 +69,8 @@ struct clk { ...@@ -65,6 +69,8 @@ struct clk {
#define CLK_ENABLE_REG_16BIT BIT(2) #define CLK_ENABLE_REG_16BIT BIT(2)
#define CLK_ENABLE_REG_8BIT BIT(3) #define CLK_ENABLE_REG_8BIT BIT(3)
#define CLK_MASK_DIV_ON_DISABLE BIT(4)
#define CLK_ENABLE_REG_MASK (CLK_ENABLE_REG_32BIT | \ #define CLK_ENABLE_REG_MASK (CLK_ENABLE_REG_32BIT | \
CLK_ENABLE_REG_16BIT | \ CLK_ENABLE_REG_16BIT | \
CLK_ENABLE_REG_8BIT) CLK_ENABLE_REG_8BIT)
...@@ -146,14 +152,17 @@ static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr) ...@@ -146,14 +152,17 @@ static inline int __deprecated sh_clk_mstp32_register(struct clk *clks, int nr)
.enable_reg = (void __iomem *)_reg, \ .enable_reg = (void __iomem *)_reg, \
.enable_bit = _shift, \ .enable_bit = _shift, \
.arch_flags = _div_bitmap, \ .arch_flags = _div_bitmap, \
.div_mask = SH_CLK_DIV4_MSK, \
.flags = _flags, \ .flags = _flags, \
} }
struct clk_div4_table { struct clk_div_table {
struct clk_div_mult_table *div_mult_table; struct clk_div_mult_table *div_mult_table;
void (*kick)(struct clk *clk); void (*kick)(struct clk *clk);
}; };
#define clk_div4_table clk_div_table
int sh_clk_div4_register(struct clk *clks, int nr, int sh_clk_div4_register(struct clk *clks, int nr,
struct clk_div4_table *table); struct clk_div4_table *table);
int sh_clk_div4_enable_register(struct clk *clks, int nr, int sh_clk_div4_enable_register(struct clk *clks, int nr,
...@@ -165,7 +174,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr, ...@@ -165,7 +174,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
_num_parents, _src_shift, _src_width) \ _num_parents, _src_shift, _src_width) \
{ \ { \
.enable_reg = (void __iomem *)_reg, \ .enable_reg = (void __iomem *)_reg, \
.flags = _flags, \ .enable_bit = 0, /* unused */ \
.flags = _flags | CLK_MASK_DIV_ON_DISABLE, \
.div_mask = SH_CLK_DIV6_MSK, \
.parent_table = _parents, \ .parent_table = _parents, \
.parent_num = _num_parents, \ .parent_num = _num_parents, \
.src_shift = _src_shift, \ .src_shift = _src_shift, \
...@@ -176,7 +187,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr, ...@@ -176,7 +187,9 @@ int sh_clk_div4_reparent_register(struct clk *clks, int nr,
{ \ { \
.parent = _parent, \ .parent = _parent, \
.enable_reg = (void __iomem *)_reg, \ .enable_reg = (void __iomem *)_reg, \
.flags = _flags, \ .enable_bit = 0, /* unused */ \
.div_mask = SH_CLK_DIV6_MSK, \
.flags = _flags | CLK_MASK_DIV_ON_DISABLE, \
} }
int sh_clk_div6_register(struct clk *clks, int nr); int sh_clk_div6_register(struct clk *clks, int nr);
......
...@@ -11,22 +11,24 @@ ...@@ -11,22 +11,24 @@
#ifndef __SH_PFC_H #ifndef __SH_PFC_H
#define __SH_PFC_H #define __SH_PFC_H
#include <linux/stringify.h>
#include <asm-generic/gpio.h> #include <asm-generic/gpio.h>
typedef unsigned short pinmux_enum_t; typedef unsigned short pinmux_enum_t;
typedef unsigned short pinmux_flag_t; typedef unsigned short pinmux_flag_t;
#define PINMUX_TYPE_NONE 0 enum {
#define PINMUX_TYPE_FUNCTION 1 PINMUX_TYPE_NONE,
#define PINMUX_TYPE_GPIO 2
#define PINMUX_TYPE_OUTPUT 3
#define PINMUX_TYPE_INPUT 4
#define PINMUX_TYPE_INPUT_PULLUP 5
#define PINMUX_TYPE_INPUT_PULLDOWN 6
#define PINMUX_FLAG_TYPE (0x7) PINMUX_TYPE_FUNCTION,
#define PINMUX_FLAG_WANT_PULLUP (1 << 3) PINMUX_TYPE_GPIO,
#define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) PINMUX_TYPE_OUTPUT,
PINMUX_TYPE_INPUT,
PINMUX_TYPE_INPUT_PULLUP,
PINMUX_TYPE_INPUT_PULLDOWN,
PINMUX_FLAG_TYPE, /* must be last */
};
#define PINMUX_FLAG_DBIT_SHIFT 5 #define PINMUX_FLAG_DBIT_SHIFT 5
#define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT) #define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT)
...@@ -36,9 +38,12 @@ typedef unsigned short pinmux_flag_t; ...@@ -36,9 +38,12 @@ typedef unsigned short pinmux_flag_t;
struct pinmux_gpio { struct pinmux_gpio {
pinmux_enum_t enum_id; pinmux_enum_t enum_id;
pinmux_flag_t flags; pinmux_flag_t flags;
const char *name;
}; };
#define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark } #define PINMUX_GPIO(gpio, data_or_mark) \
[gpio] = { .name = __stringify(gpio), .enum_id = data_or_mark, .flags = PINMUX_TYPE_NONE }
#define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0 #define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0
struct pinmux_cfg_reg { struct pinmux_cfg_reg {
...@@ -89,7 +94,7 @@ struct pfc_window { ...@@ -89,7 +94,7 @@ struct pfc_window {
unsigned long size; unsigned long size;
}; };
struct pinmux_info { struct sh_pfc {
char *name; char *name;
pinmux_enum_t reserved_id; pinmux_enum_t reserved_id;
struct pinmux_range data; struct pinmux_range data;
...@@ -112,17 +117,45 @@ struct pinmux_info { ...@@ -112,17 +117,45 @@ struct pinmux_info {
struct pinmux_irq *gpio_irq; struct pinmux_irq *gpio_irq;
unsigned int gpio_irq_size; unsigned int gpio_irq_size;
spinlock_t lock;
struct resource *resource; struct resource *resource;
unsigned int num_resources; unsigned int num_resources;
struct pfc_window *window; struct pfc_window *window;
unsigned long unlock_reg; unsigned long unlock_reg;
struct gpio_chip chip;
}; };
int register_pinmux(struct pinmux_info *pip); /* XXX compat for now */
int unregister_pinmux(struct pinmux_info *pip); #define pinmux_info sh_pfc
/* drivers/sh/pfc/gpio.c */
int sh_pfc_register_gpiochip(struct sh_pfc *pfc);
/* drivers/sh/pfc/pinctrl.c */
int sh_pfc_register_pinctrl(struct sh_pfc *pfc);
/* drivers/sh/pfc/core.c */
int register_sh_pfc(struct sh_pfc *pfc);
int sh_pfc_read_bit(struct pinmux_data_reg *dr, unsigned long in_pos);
void sh_pfc_write_bit(struct pinmux_data_reg *dr, unsigned long in_pos,
unsigned long value);
int sh_pfc_get_data_reg(struct sh_pfc *pfc, unsigned gpio,
struct pinmux_data_reg **drp, int *bitp);
int sh_pfc_gpio_to_enum(struct sh_pfc *pfc, unsigned gpio, int pos,
pinmux_enum_t *enum_idp);
int sh_pfc_config_gpio(struct sh_pfc *pfc, unsigned gpio, int pinmux_type,
int cfg_mode);
/* xxx */
static inline int register_pinmux(struct pinmux_info *pip)
{
struct sh_pfc *pfc = pip;
return register_sh_pfc(pfc);
}
enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE };
/* helper macro for port */ /* helper macro for port */
#define PORT_1(fn, pfx, sfx) fn(pfx, sfx) #define PORT_1(fn, pfx, sfx) fn(pfx, sfx)
......
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