From 006e983bbc805431c44e2135e13841f66059a045 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:22 +0530 Subject: DRIVERS: IRQCHIP: IRQ-GIC: Add support for routable irqs In some socs the gic can be preceded by a crossbar IP which routes the peripheral interrupts to the gic inputs. The peripheral interrupts are associated with a fixed crossbar input line and the crossbar routes that to one of the free gic input line. The DT entries for peripherals provides the fixed crossbar input line as its interrupt number and the mapping code should associate this with a free gic input line. This patch adds the support inside the gic irqchip to handle such routable irqs. The routable irqs are registered in a linear domain. The registered routable domain's callback should be implemented to get a free irq and to configure the IP to route it. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Reviewed-by: Thomas Gleixner Acked-by: Santosh Shilimkar Acked-by: Linus Walleij --- Documentation/devicetree/bindings/arm/gic.txt | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt index bae0d87a38b..5573c08d318 100644 --- a/Documentation/devicetree/bindings/arm/gic.txt +++ b/Documentation/devicetree/bindings/arm/gic.txt @@ -50,6 +50,11 @@ Optional regions, used when the GIC doesn't have banked registers. The offset is cpu-offset * cpu-nr. +- arm,routable-irqs : Total number of gic irq inputs which are not directly + connected from the peripherals, but are routed dynamically + by a crossbar/multiplexer preceding the GIC. The GIC irq + input line is assigned dynamically when the corresponding + peripheral's crossbar line is mapped. Example: intc: interrupt-controller@fff11000 { @@ -57,6 +62,7 @@ Example: #interrupt-cells = <3>; #address-cells = <1>; interrupt-controller; + arm,routable-irqs = <160>; reg = <0xfff11000 0x1000>, <0xfff10100 0x100>; }; -- cgit v1.2.3-70-g09d2 From 96ca848ef7ea1be7e92d1cceb34ef3aa86053828 Mon Sep 17 00:00:00 2001 From: Sricharan R Date: Tue, 3 Dec 2013 15:57:23 +0530 Subject: DRIVERS: IRQCHIP: CROSSBAR: Add support for Crossbar IP Some socs have a large number of interrupts requests to service the needs of its many peripherals and subsystems. All of the interrupt lines from the subsystems are not needed at the same time, so they have to be muxed to the irq-controller appropriately. In such places a interrupt controllers are preceded by an CROSSBAR that provides flexibility in muxing the device requests to the controller inputs. This driver takes care a allocating a free irq and then configuring the crossbar IP as a part of the mpu's irqchip callbacks. crossbar_init should be called right before the irqchip_init, so that it is setup to handle the irqchip callbacks. Cc: Thomas Gleixner Cc: Linus Walleij Cc: Santosh Shilimkar Cc: Russell King Cc: Tony Lindgren Cc: Rajendra Nayak Cc: Marc Zyngier Cc: Grant Likely Cc: Rob Herring Signed-off-by: Sricharan R Acked-by: Kumar Gala (for DT binding portion) Acked-by: Santosh Shilimkar Acked-by: Linus Walleij Acked-by: Thomas Gleixner --- .../devicetree/bindings/arm/omap/crossbar.txt | 27 +++ drivers/irqchip/Kconfig | 8 + drivers/irqchip/Makefile | 1 + drivers/irqchip/irq-crossbar.c | 208 +++++++++++++++++++++ include/linux/irqchip/irq-crossbar.h | 11 ++ 5 files changed, 255 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/omap/crossbar.txt create mode 100644 drivers/irqchip/irq-crossbar.c create mode 100644 include/linux/irqchip/irq-crossbar.h (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/arm/omap/crossbar.txt b/Documentation/devicetree/bindings/arm/omap/crossbar.txt new file mode 100644 index 00000000000..fb88585cfb9 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/omap/crossbar.txt @@ -0,0 +1,27 @@ +Some socs have a large number of interrupts requests to service +the needs of its many peripherals and subsystems. All of the +interrupt lines from the subsystems are not needed at the same +time, so they have to be muxed to the irq-controller appropriately. +In such places a interrupt controllers are preceded by an CROSSBAR +that provides flexibility in muxing the device requests to the controller +inputs. + +Required properties: +- compatible : Should be "ti,irq-crossbar" +- reg: Base address and the size of the crossbar registers. +- ti,max-irqs: Total number of irqs available at the interrupt controller. +- ti,reg-size: Size of a individual register in bytes. Every individual + register is assumed to be of same size. Valid sizes are 1, 2, 4. +- ti,irqs-reserved: List of the reserved irq lines that are not muxed using + crossbar. These interrupt lines are reserved in the soc, + so crossbar bar driver should not consider them as free + lines. + +Examples: + crossbar_mpu: @4a020000 { + compatible = "ti,irq-crossbar"; + reg = <0x4a002a48 0x130>; + ti,max-irqs = <160>; + ti,reg-size = <2>; + ti,irqs-reserved = <0 1 2 3 5 6 131 132 139 140>; + }; diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index 61ffdca96e2..111068782da 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -69,3 +69,11 @@ config VERSATILE_FPGA_IRQ_NR config XTENSA_MX bool select IRQ_DOMAIN + +config IRQ_CROSSBAR + bool + help + Support for a CROSSBAR ip that preceeds the main interrupt controller. + The primary irqchip invokes the crossbar's callback which inturn allocates + a free irq and configures the IP. Thus the peripheral interrupts are + routed to one of the free irqchip interrupt lines. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 86b484cb3ec..3e776cb8dd4 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o +obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o diff --git a/drivers/irqchip/irq-crossbar.c b/drivers/irqchip/irq-crossbar.c new file mode 100644 index 00000000000..fc817d28d1f --- /dev/null +++ b/drivers/irqchip/irq-crossbar.c @@ -0,0 +1,208 @@ +/* + * drivers/irqchip/irq-crossbar.c + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Sricharan R + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include + +#define IRQ_FREE -1 +#define GIC_IRQ_START 32 + +/* + * @int_max: maximum number of supported interrupts + * @irq_map: array of interrupts to crossbar number mapping + * @crossbar_base: crossbar base address + * @register_offsets: offsets for each irq number + */ +struct crossbar_device { + uint int_max; + uint *irq_map; + void __iomem *crossbar_base; + int *register_offsets; + void (*write) (int, int); +}; + +static struct crossbar_device *cb; + +static inline void crossbar_writel(int irq_no, int cb_no) +{ + writel(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writew(int irq_no, int cb_no) +{ + writew(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline void crossbar_writeb(int irq_no, int cb_no) +{ + writeb(cb_no, cb->crossbar_base + cb->register_offsets[irq_no]); +} + +static inline int allocate_free_irq(int cb_no) +{ + int i; + + for (i = 0; i < cb->int_max; i++) { + if (cb->irq_map[i] == IRQ_FREE) { + cb->irq_map[i] = cb_no; + return i; + } + } + + return -ENODEV; +} + +static int crossbar_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hw) +{ + cb->write(hw - GIC_IRQ_START, cb->irq_map[hw - GIC_IRQ_START]); + return 0; +} + +static void crossbar_domain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_hw_number_t hw = irq_get_irq_data(irq)->hwirq; + + if (hw > GIC_IRQ_START) + cb->irq_map[hw - GIC_IRQ_START] = IRQ_FREE; +} + +static int crossbar_domain_xlate(struct irq_domain *d, + struct device_node *controller, + const u32 *intspec, unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + unsigned long ret; + + ret = allocate_free_irq(intspec[1]); + + if (IS_ERR_VALUE(ret)) + return ret; + + *out_hwirq = ret + GIC_IRQ_START; + return 0; +} + +const struct irq_domain_ops routable_irq_domain_ops = { + .map = crossbar_domain_map, + .unmap = crossbar_domain_unmap, + .xlate = crossbar_domain_xlate +}; + +static int __init crossbar_of_init(struct device_node *node) +{ + int i, size, max, reserved = 0, entry; + const __be32 *irqsr; + + cb = kzalloc(sizeof(struct cb_device *), GFP_KERNEL); + + if (!cb) + return -ENOMEM; + + cb->crossbar_base = of_iomap(node, 0); + if (!cb->crossbar_base) + goto err1; + + of_property_read_u32(node, "ti,max-irqs", &max); + cb->irq_map = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->irq_map) + goto err2; + + cb->int_max = max; + + for (i = 0; i < max; i++) + cb->irq_map[i] = IRQ_FREE; + + /* Get and mark reserved irqs */ + irqsr = of_get_property(node, "ti,irqs-reserved", &size); + if (irqsr) { + size /= sizeof(__be32); + + for (i = 0; i < size; i++) { + of_property_read_u32_index(node, + "ti,irqs-reserved", + i, &entry); + if (entry > max) { + pr_err("Invalid reserved entry\n"); + goto err3; + } + cb->irq_map[entry] = 0; + } + } + + cb->register_offsets = kzalloc(max * sizeof(int), GFP_KERNEL); + if (!cb->register_offsets) + goto err3; + + of_property_read_u32(node, "ti,reg-size", &size); + + switch (size) { + case 1: + cb->write = crossbar_writeb; + break; + case 2: + cb->write = crossbar_writew; + break; + case 4: + cb->write = crossbar_writel; + break; + default: + pr_err("Invalid reg-size property\n"); + goto err4; + break; + } + + /* + * Register offsets are not linear because of the + * reserved irqs. so find and store the offsets once. + */ + for (i = 0; i < max; i++) { + if (!cb->irq_map[i]) + continue; + + cb->register_offsets[i] = reserved; + reserved += size; + } + + register_routable_domain_ops(&routable_irq_domain_ops); + return 0; + +err4: + kfree(cb->register_offsets); +err3: + kfree(cb->irq_map); +err2: + iounmap(cb->crossbar_base); +err1: + kfree(cb); + return -ENOMEM; +} + +static const struct of_device_id crossbar_match[] __initconst = { + { .compatible = "ti,irq-crossbar" }, + {} +}; + +int __init irqcrossbar_init(void) +{ + struct device_node *np; + np = of_find_matching_node(NULL, crossbar_match); + if (!np) + return -ENODEV; + + crossbar_of_init(np); + return 0; +} diff --git a/include/linux/irqchip/irq-crossbar.h b/include/linux/irqchip/irq-crossbar.h new file mode 100644 index 00000000000..e5537b81df8 --- /dev/null +++ b/include/linux/irqchip/irq-crossbar.h @@ -0,0 +1,11 @@ +/* + * drivers/irqchip/irq-crossbar.h + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +int irqcrossbar_init(void); -- cgit v1.2.3-70-g09d2 From 09c978bc7bdcfc3db91801454273a4330e1933bf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 10 Jan 2014 15:57:27 +0100 Subject: ARM: integrator: switch to fetch clocks from device tree This atomic commit changes the Integrator clock implementation and the machines to register clocks from the device tree and use these instead of the previous hard-coded clocks. In the clock implementation all hard-coded clocks and the special initialization function call goes away, and is replaced by two compatible strings for the two clocks available on the core module. Cc: Mike Turquette Signed-off-by: Linus Walleij --- .../devicetree/bindings/clock/arm-integrator.txt | 34 +++++++++ arch/arm/mach-integrator/integrator_ap.c | 19 +++-- arch/arm/mach-integrator/integrator_cp.c | 6 -- drivers/clk/versatile/clk-integrator.c | 80 +++++++++------------- include/linux/platform_data/clk-integrator.h | 1 - 5 files changed, 80 insertions(+), 60 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/arm-integrator.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/clock/arm-integrator.txt b/Documentation/devicetree/bindings/clock/arm-integrator.txt new file mode 100644 index 00000000000..652914b17b9 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/arm-integrator.txt @@ -0,0 +1,34 @@ +Clock bindings for ARM Integrator Core Module clocks + +Auxilary Oscillator Clock + +This is a configurable clock fed from a 24 MHz chrystal, +used for generating e.g. video clocks. It is located on the +core module and there is only one of these. + +This clock node *must* be a subnode of the core module, since +it obtains the base address for it's address range from its +parent node. + + +Required properties: +- compatible: must be "arm,integrator-cm-auxosc" +- #clock-cells: must be <0> + +Optional properties: +- clocks: parent clock(s) + +Example: + +core-module@10000000 { + xtal24mhz: xtal24mhz@24M { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <24000000>; + }; + auxosc: cm_aux_osc@25M { + #clock-cells = <0>; + compatible = "arm,integrator-cm-auxosc"; + clocks = <&xtal24mhz>; + }; +}; diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 17c0fe62743..fedcd2fab09 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -402,10 +403,7 @@ static void __init ap_of_timer_init(void) struct clk *clk; unsigned long rate; - clk = clk_get_sys("ap_timer", NULL); - BUG_ON(IS_ERR(clk)); - clk_prepare_enable(clk); - rate = clk_get_rate(clk); + of_clk_init(NULL); err = of_property_read_string(of_aliases, "arm,timer-primary", &path); @@ -415,6 +413,12 @@ static void __init ap_of_timer_init(void) base = of_iomap(node, 0); if (WARN_ON(!base)) return; + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); integrator_clocksource_init(rate, base); @@ -427,6 +431,12 @@ static void __init ap_of_timer_init(void) if (WARN_ON(!base)) return; irq = irq_of_parse_and_map(node, 0); + + clk = of_clk_get(node, 0); + BUG_ON(IS_ERR(clk)); + clk_prepare_enable(clk); + rate = clk_get_rate(clk); + writel(0, base + TIMER_CTRL); integrator_clockevent_init(rate, base, irq); } @@ -440,7 +450,6 @@ static void __init ap_init_irq_of(void) { cm_init(); of_irq_init(fpga_irq_of_match); - integrator_clk_init(false); } /* For the Device Tree, add in the UART callbacks as AUXDATA */ diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c index a3ef961e4a9..0ad5f60598c 100644 --- a/arch/arm/mach-integrator/integrator_cp.c +++ b/arch/arm/mach-integrator/integrator_cp.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -33,8 +32,6 @@ #include #include #include -#include -#include #include @@ -43,8 +40,6 @@ #include #include -#include - #include #include @@ -250,7 +245,6 @@ static void __init intcp_init_irq_of(void) { cm_init(); of_irq_init(fpga_irq_of_match); - integrator_clk_init(true); } /* diff --git a/drivers/clk/versatile/clk-integrator.c b/drivers/clk/versatile/clk-integrator.c index bda8967e09c..19864b5690e 100644 --- a/drivers/clk/versatile/clk-integrator.c +++ b/drivers/clk/versatile/clk-integrator.c @@ -10,20 +10,17 @@ #include #include #include -#include - -#include -#include +#include +#include #include "clk-icst.h" -/* - * Implementation of the ARM Integrator/AP and Integrator/CP clock tree. - * Inspired by portions of: - * plat-versatile/clock.c and plat-versatile/include/plat/clock.h - */ +#define INTEGRATOR_HDR_LOCK_OFFSET 0x14 -static const struct icst_params cp_auxvco_params = { +/* Base offset for the core module */ +static void __iomem *cm_base; + +static const struct icst_params cp_auxosc_params = { .ref = 24000000, .vco_max = ICST525_VCO_MAX_5V, .vco_min = ICST525_VCO_MIN, @@ -35,50 +32,37 @@ static const struct icst_params cp_auxvco_params = { .idx2s = icst525_idx2s, }; -static const struct clk_icst_desc __initdata cp_icst_desc = { - .params = &cp_auxvco_params, +static const struct clk_icst_desc __initdata cm_auxosc_desc = { + .params = &cp_auxosc_params, .vco_offset = 0x1c, .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, }; -/* - * integrator_clk_init() - set up the integrator clock tree - * @is_cp: pass true if it's the Integrator/CP else AP is assumed - */ -void __init integrator_clk_init(bool is_cp) +static void __init of_integrator_cm_osc_setup(struct device_node *np) { - struct clk *clk; - - /* APB clock dummy */ - clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); - clk_register_clkdev(clk, "apb_pclk", NULL); - - /* UART reference clock */ - clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, - 14745600); - clk_register_clkdev(clk, NULL, "uart0"); - clk_register_clkdev(clk, NULL, "uart1"); - if (is_cp) - clk_register_clkdev(clk, NULL, "mmci"); - - /* 24 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk24mhz", NULL, CLK_IS_ROOT, - 24000000); - clk_register_clkdev(clk, NULL, "kmi0"); - clk_register_clkdev(clk, NULL, "kmi1"); - if (!is_cp) - clk_register_clkdev(clk, NULL, "ap_timer"); + struct clk *clk = ERR_PTR(-EINVAL); + const char *clk_name = np->name; + const struct clk_icst_desc *desc = &cm_auxosc_desc; - if (!is_cp) - return; + if (!cm_base) { + /* Remap the core module base if not done yet */ + struct device_node *parent; - /* 1 MHz clock */ - clk = clk_register_fixed_rate(NULL, "clk1mhz", NULL, CLK_IS_ROOT, - 1000000); - clk_register_clkdev(clk, NULL, "sp804"); + parent = of_get_parent(np); + if (!np) { + pr_err("no parent on core module clock\n"); + return; + } + cm_base = of_iomap(parent, 0); + if (!cm_base) { + pr_err("could not remap core module base\n"); + return; + } + } - /* ICST VCO clock used on the Integrator/CP CLCD */ - clk = icst_clk_register(NULL, &cp_icst_desc, "icst", - __io_address(INTEGRATOR_HDR_BASE)); - clk_register_clkdev(clk, NULL, "clcd"); + clk = icst_clk_register(NULL, desc, clk_name, cm_base); + if (!IS_ERR(clk)) + of_clk_add_provider(np, of_clk_src_simple_get, clk); } +CLK_OF_DECLARE(integrator_cm_auxosc_clk, + "arm,integrator-cm-auxosc", of_integrator_cm_osc_setup); diff --git a/include/linux/platform_data/clk-integrator.h b/include/linux/platform_data/clk-integrator.h index 280edac9d0a..addd48cac62 100644 --- a/include/linux/platform_data/clk-integrator.h +++ b/include/linux/platform_data/clk-integrator.h @@ -1,3 +1,2 @@ -void integrator_clk_init(bool is_cp); void integrator_impd1_clk_init(void __iomem *base, unsigned int id); void integrator_impd1_clk_exit(unsigned int id); -- cgit v1.2.3-70-g09d2 From e97662e1e28da0da0702db213931d8f9a580970a Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Feb 2014 20:00:24 -0300 Subject: watchdog: orion: Handle the interrupt so it's properly acked DT-enabled plaforms, where the irqchip driver for the brigde interrupt controller is available, can handle the watchdog IRQ properly. Therefore, request the interrupt and add a dummy handler that merely calls panic(). This is done in order to have an initial 'ack' of the interruption, which clears the watchdog state. Furthermore, since some platforms don't have such IRQ, this commit makes the interrupt specification optional. Tested-by: Sebastian Hesselbarth Tested-by: Willy Tarreau Signed-off-by: Ezequiel Garcia Acked-by: Wim Van Sebroeck Tested-By: Jason Gunthorpe Signed-off-by: Jason Cooper --- .../devicetree/bindings/watchdog/marvel.txt | 2 ++ drivers/watchdog/orion_wdt.c | 24 +++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 5dc8d30061c..0731fbd2de8 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -7,6 +7,7 @@ Required Properties: Optional properties: +- interrupts : Contains the IRQ for watchdog expiration - timeout-sec : Contains the watchdog timeout in seconds Example: @@ -14,6 +15,7 @@ Example: wdt@20300 { compatible = "marvell,orion-wdt"; reg = <0x20300 0x28>; + interrupts = <3>; timeout-sec = <10>; status = "okay"; }; diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index e10b0b1accc..b7067acd43a 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -119,10 +120,16 @@ static struct watchdog_device orion_wdt = { .min_timeout = 1, }; +static irqreturn_t orion_wdt_irq(int irq, void *devid) +{ + panic("Watchdog Timeout"); + return IRQ_HANDLED; +} + static int orion_wdt_probe(struct platform_device *pdev) { struct resource *res; - int ret; + int ret, irq; clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { @@ -161,6 +168,21 @@ static int orion_wdt_probe(struct platform_device *pdev) if (!orion_wdt_enabled()) orion_wdt_stop(&orion_wdt); + /* Request the IRQ only after the watchdog is disabled */ + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + /* + * Not all supported platforms specify an interrupt for the + * watchdog, so let's make it optional. + */ + ret = devm_request_irq(&pdev->dev, irq, orion_wdt_irq, 0, + pdev->name, &orion_wdt); + if (ret < 0) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto disable_clk; + } + } + watchdog_set_nowayout(&orion_wdt, nowayout); ret = watchdog_register_device(&orion_wdt); if (ret) -- cgit v1.2.3-70-g09d2 From 868eb61602d9c020fc9e21b42f3ccd301b36b94d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Feb 2014 20:00:25 -0300 Subject: watchdog: orion: Make RSTOUT register a separate resource In order to support other SoC, it's required to distinguish the 'control' timer register, from the 'rstout' register that enables system reset on watchdog expiration. To prevent a compatibility break, this commit adds a fallback to a hardcoded RSTOUT address. Reviewed-by: Guenter Roeck Tested-by: Sebastian Hesselbarth Tested-by: Willy Tarreau Signed-off-by: Ezequiel Garcia Acked-by: Wim Van Sebroeck Tested-By: Jason Gunthorpe Signed-off-by: Jason Cooper --- .../devicetree/bindings/watchdog/marvel.txt | 6 ++- arch/arm/mach-dove/include/mach/bridge-regs.h | 1 + arch/arm/mach-kirkwood/include/mach/bridge-regs.h | 1 + arch/arm/mach-mv78xx0/include/mach/bridge-regs.h | 1 + arch/arm/mach-orion5x/include/mach/bridge-regs.h | 1 + arch/arm/plat-orion/common.c | 10 +++-- drivers/watchdog/orion_wdt.c | 47 ++++++++++++++++++++-- 7 files changed, 58 insertions(+), 9 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 0731fbd2de8..1544fe991d2 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -3,7 +3,9 @@ Required Properties: - Compatibility : "marvell,orion-wdt" -- reg : Address of the timer registers +- reg : Should contain two entries: first one with the + timer control address, second one with the + rstout enable address. Optional properties: @@ -14,7 +16,7 @@ Example: wdt@20300 { compatible = "marvell,orion-wdt"; - reg = <0x20300 0x28>; + reg = <0x20300 0x28>, <0x20108 0x4>; interrupts = <3>; timeout-sec = <10>; status = "okay"; diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h index 5362df3df89..f4a5b34489b 100644 --- a/arch/arm/mach-dove/include/mach/bridge-regs.h +++ b/arch/arm/mach-dove/include/mach/bridge-regs.h @@ -21,6 +21,7 @@ #define CPU_CTRL_PCIE1_LINK 0x00000008 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index 8b9d1c9ff19..60f64218d6a 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h @@ -21,6 +21,7 @@ #define CPU_RESET 0x00000002 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h index 5f03484584d..e20d6da234a 100644 --- a/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h +++ b/arch/arm/mach-mv78xx0/include/mach/bridge-regs.h @@ -15,6 +15,7 @@ #define L2_WRITETHROUGH 0x00020000 #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) +#define RSTOUTn_MASK_PHYS (BRIDGE_PHYS_BASE + 0x0108) #define SOFT_RESET_OUT_EN 0x00000004 #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h index f727d03f168..5766e3fbff6 100644 --- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h +++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h @@ -18,6 +18,7 @@ #define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104) #define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108) +#define RSTOUTn_MASK_PHYS (ORION5X_BRIDGE_PHYS_BASE + 0x108) #define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c) diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 830ff07f338..3ec6e8e8d36 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -595,14 +595,16 @@ void __init orion_spi_1_init(unsigned long mapbase) /***************************************************************************** * Watchdog ****************************************************************************/ -static struct resource orion_wdt_resource = - DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x28); +static struct resource orion_wdt_resource[] = { + DEFINE_RES_MEM(TIMER_PHYS_BASE, 0x04), + DEFINE_RES_MEM(RSTOUTn_MASK_PHYS, 0x04), +}; static struct platform_device orion_wdt_device = { .name = "orion_wdt", .id = -1, - .num_resources = 1, - .resource = &orion_wdt_resource, + .num_resources = ARRAY_SIZE(orion_wdt_resource), + .resource = orion_wdt_resource, }; void __init orion_wdt_init(void) diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index b7067acd43a..6061b838d39 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -26,6 +26,12 @@ #include #include +/* RSTOUT mask register physical address for Orion5x, Kirkwood and Dove */ +#define ORION_RSTOUT_MASK_OFFSET 0x20108 + +/* Internal registers can be configured at any 1 MiB aligned address */ +#define INTERNAL_REGS_MASK ~(SZ_1M - 1) + /* * Watchdog timer block registers. */ @@ -44,6 +50,7 @@ static unsigned int wdt_max_duration; /* (seconds) */ static struct clk *clk; static unsigned int wdt_tclk; static void __iomem *wdt_reg; +static void __iomem *wdt_rstout; static int orion_wdt_ping(struct watchdog_device *wdt_dev) { @@ -64,14 +71,14 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev) atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, WDT_EN); /* Enable reset on watchdog */ - atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN); + atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, WDT_RESET_OUT_EN); return 0; } static int orion_wdt_stop(struct watchdog_device *wdt_dev) { /* Disable reset on watchdog */ - atomic_io_modify(RSTOUTn_MASK, WDT_RESET_OUT_EN, 0); + atomic_io_modify(wdt_rstout, WDT_RESET_OUT_EN, 0); /* Disable watchdog timer */ atomic_io_modify(wdt_reg + TIMER_CTRL, WDT_EN, 0); @@ -82,7 +89,7 @@ static int orion_wdt_enabled(void) { bool enabled, running; - enabled = readl(RSTOUTn_MASK) & WDT_RESET_OUT_EN; + enabled = readl(wdt_rstout) & WDT_RESET_OUT_EN; running = readl(wdt_reg + TIMER_CTRL) & WDT_EN; return enabled && running; @@ -126,6 +133,33 @@ static irqreturn_t orion_wdt_irq(int irq, void *devid) return IRQ_HANDLED; } +/* + * The original devicetree binding for this driver specified only + * one memory resource, so in order to keep DT backwards compatibility + * we try to fallback to a hardcoded register address, if the resource + * is missing from the devicetree. + */ +static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev, + phys_addr_t internal_regs) +{ + struct resource *res; + phys_addr_t rstout; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (res) + return devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + /* This workaround works only for "orion-wdt", DT-enabled */ + if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt")) + return NULL; + + rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; + + WARN(1, FW_BUG "falling back to harcoded RSTOUT reg 0x%x\n", rstout); + return devm_ioremap(&pdev->dev, rstout, 0x4); +} + static int orion_wdt_probe(struct platform_device *pdev) { struct resource *res; @@ -153,6 +187,13 @@ static int orion_wdt_probe(struct platform_device *pdev) goto disable_clk; } + wdt_rstout = orion_wdt_ioremap_rstout(pdev, res->start & + INTERNAL_REGS_MASK); + if (!wdt_rstout) { + ret = -ENODEV; + goto disable_clk; + } + wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; orion_wdt.timeout = wdt_max_duration; -- cgit v1.2.3-70-g09d2 From 463f96e0cdacce5be9bfdd4cc81e7225347cdc31 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Feb 2014 20:00:31 -0300 Subject: watchdog: orion: Add support for Armada 370 and Armada XP SoC Using the added infrastructure for handling SoC differences, this commit adds support for the watchdog controller available in Armada 370 and Armada XP SoCs. Also, and because the AXP clock initialization uses of_clk_get_by_name, this commit changes the orion clock initialization to use clk_get() and adds a proper clk_put() on the common exit/error paths. Reviewed-by: Guenter Roeck Tested-by: Sebastian Hesselbarth Tested-by: Willy Tarreau Signed-off-by: Ezequiel Garcia Acked-by: Wim Van Sebroeck Tested-By: Jason Gunthorpe Signed-off-by: Jason Cooper --- .../devicetree/bindings/watchdog/marvel.txt | 3 + drivers/watchdog/orion_wdt.c | 106 ++++++++++++++++++++- 2 files changed, 107 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt index 1544fe991d2..de11eb4c121 100644 --- a/Documentation/devicetree/bindings/watchdog/marvel.txt +++ b/Documentation/devicetree/bindings/watchdog/marvel.txt @@ -3,6 +3,9 @@ Required Properties: - Compatibility : "marvell,orion-wdt" + "marvell,armada-370-wdt" + "marvell,armada-xp-wdt" + - reg : Should contain two entries: first one with the timer control address, second one with the rstout enable address. diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 392529785b4..15321aa0bb9 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -36,9 +36,17 @@ * Watchdog timer block registers. */ #define TIMER_CTRL 0x0000 +#define TIMER_A370_STATUS 0x04 #define WDT_MAX_CYCLE_COUNT 0xffffffff +#define WDT_A370_RATIO_MASK(v) ((v) << 16) +#define WDT_A370_RATIO_SHIFT 5 +#define WDT_A370_RATIO (1 << WDT_A370_RATIO_SHIFT) + +#define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define WDT_A370_EXPIRED BIT(31) + static bool nowayout = WATCHDOG_NOWAYOUT; static int heartbeat = -1; /* module parameter (seconds) */ @@ -67,12 +75,60 @@ static int orion_wdt_clock_init(struct platform_device *pdev, { int ret; - dev->clk = devm_clk_get(&pdev->dev, NULL); + dev->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) return PTR_ERR(dev->clk); ret = clk_prepare_enable(dev->clk); - if (ret) + if (ret) { + clk_put(dev->clk); return ret; + } + + dev->clk_rate = clk_get_rate(dev->clk); + return 0; +} + +static int armada370_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) +{ + int ret; + + dev->clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + /* Setup watchdog input clock */ + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT), + WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT)); + + dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO; + return 0; +} + +static int armadaxp_wdt_clock_init(struct platform_device *pdev, + struct orion_watchdog *dev) +{ + int ret; + + dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed"); + if (IS_ERR(dev->clk)) + return PTR_ERR(dev->clk); + ret = clk_prepare_enable(dev->clk); + if (ret) { + clk_put(dev->clk); + return ret; + } + + /* Enable the fixed watchdog clock input */ + atomic_io_modify(dev->reg + TIMER_CTRL, + WDT_AXP_FIXED_ENABLE_BIT, + WDT_AXP_FIXED_ENABLE_BIT); dev->clk_rate = clk_get_rate(dev->clk); return 0; @@ -87,6 +143,26 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev) return 0; } +static int armada370_start(struct watchdog_device *wdt_dev) +{ + struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); + + /* Set watchdog duration */ + writel(dev->clk_rate * wdt_dev->timeout, + dev->reg + dev->data->wdt_counter_offset); + + /* Clear the watchdog expiration bit */ + atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0); + + /* Enable watchdog timer */ + atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, + dev->data->wdt_enable_bit); + + atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, + dev->data->rstout_enable_bit); + return 0; +} + static int orion_start(struct watchdog_device *wdt_dev) { struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); @@ -205,11 +281,35 @@ static const struct orion_watchdog_data orion_data = { .start = orion_start, }; +static const struct orion_watchdog_data armada370_data = { + .rstout_enable_bit = BIT(8), + .wdt_enable_bit = BIT(8), + .wdt_counter_offset = 0x34, + .clock_init = armada370_wdt_clock_init, + .start = armada370_start, +}; + +static const struct orion_watchdog_data armadaxp_data = { + .rstout_enable_bit = BIT(8), + .wdt_enable_bit = BIT(8), + .wdt_counter_offset = 0x34, + .clock_init = armadaxp_wdt_clock_init, + .start = armada370_start, +}; + static const struct of_device_id orion_wdt_of_match_table[] = { { .compatible = "marvell,orion-wdt", .data = &orion_data, }, + { + .compatible = "marvell,armada-370-wdt", + .data = &armada370_data, + }, + { + .compatible = "marvell,armada-xp-wdt", + .data = &armadaxp_data, + }, {}, }; MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); @@ -301,6 +401,7 @@ static int orion_wdt_probe(struct platform_device *pdev) disable_clk: clk_disable_unprepare(dev->clk); + clk_put(dev->clk); return ret; } @@ -311,6 +412,7 @@ static int orion_wdt_remove(struct platform_device *pdev) watchdog_unregister_device(wdt_dev); clk_disable_unprepare(dev->clk); + clk_put(dev->clk); return 0; } -- cgit v1.2.3-70-g09d2 From 7e0b4cd06201ee9dbdf2d13bfd7b8a021b414e42 Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Thu, 6 Feb 2014 16:48:43 -0600 Subject: dts: socfpga: Add DTS entry for adding the stmmac glue layer for stmmac. This patch adds the dts bindings documenation for the Altera SOCFPGA glue layer for the Synopsys STMMAC ethernet driver. Signed-off-by: Dinh Nguyen Acked-by: David S. Miller --- v3: Remove stray empty line at end of socfpga_cyclone5_socdk.dts v2: Use the dwmac-sti as an example for a glue layer and split patch up to have dts as a separate patch. Also cc dts maintainers since there is a new binding. --- .../devicetree/bindings/net/socfpga-dwmac.txt | 35 ++++++++++++++++ arch/arm/boot/dts/socfpga.dtsi | 49 +++++++++++++++------- arch/arm/boot/dts/socfpga_arria5_socdk.dts | 24 +++++++++++ arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 17 ++++++++ arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 22 +++++++++- arch/arm/boot/dts/socfpga_vt.dts | 8 ++++ 6 files changed, 138 insertions(+), 17 deletions(-) create mode 100644 Documentation/devicetree/bindings/net/socfpga-dwmac.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt new file mode 100644 index 00000000000..d53d3765b2c --- /dev/null +++ b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt @@ -0,0 +1,35 @@ +Altera SOCFPGA SoC DWMAC controller + +The device node has following properties. + +Required properties: + - compatible : Should contain "altr,socfpga-stmmac" + - altr,sysmgr-syscon : Should be the phandle to the system manager node that + encompasses the glue register, and the register offset. + +Sub-nodes: +The dwmac core should be added as subnode to SOCFPGA dwmac glue. +- dwmac : The binding details of dwmac can be found in + Documentation/devicetree/bindings/net/stmmac.txt + +Example: + +ethernet0: ethernet0 { + #address-cells = <1>; + #size-cells = <1>; + + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; + status = "disabled"; + ranges; + + gmac0: gmac0@ff700000 { + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac0_clk>; + clock-names = "stmmaceth"; + }; +}; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 537f1a5c07f..3796141fb8b 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -441,26 +441,43 @@ }; }; - gmac0: ethernet@ff700000 { - compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff700000 0x2000>; - interrupts = <0 115 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac0_clk>; - clock-names = "stmmaceth"; + ethernet0: ethernet0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; status = "disabled"; + ranges; + + gmac0: gmac0@ff700000 { + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac0_clk>; + clock-names = "stmmaceth"; + }; }; - gmac1: ethernet@ff702000 { - compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff702000 0x2000>; - interrupts = <0 120 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac1_clk>; - clock-names = "stmmaceth"; + ethernet1: ethernet1 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,socfpga-stmmac"; + altr,sysmgr-syscon = <&sysmgr 0x60>; status = "disabled"; + ranges; + + gmac1: gmac1@ff702000 { + device_type = "network"; + compatible = "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff702000 0x2000>; + interrupts = <0 120 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac1_clk>; + clock-names = "stmmaceth"; + }; }; L2: l2-cache@fffef000 { diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts index 5beffb2265f..2d6b38ba937 100644 --- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts @@ -37,4 +37,28 @@ */ ethernet0 = &gmac1; }; + + aliases { + /* this allow the ethaddr uboot environmnet variable contents + * to be added to the gmac1 device tree blob. + */ + ethernet0 = &gmac1; + }; +}; + +ðernet1 { + status = "okay"; +}; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts index 2ee52ab8cab..26c63a07f8b 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts @@ -38,3 +38,20 @@ ethernet0 = &gmac1; }; }; + +ðernet1 { + status = "okay"; +}; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; +}; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts index 50b99a2c12a..469bb5cac88 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts @@ -30,8 +30,28 @@ device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ }; + + aliases { + /* this allow the ethaddr uboot environmnet variable contents + * to be added to the gmac1 device tree blob. + */ + ethernet0 = &gmac1; + }; }; -&gmac1 { +ðernet1 { status = "okay"; }; + +&gmac1 { + phy-mode = "rgmii"; + + rxd0-skew-ps = <0>; + rxd1-skew-ps = <0>; + rxd2-skew-ps = <0>; + rxd3-skew-ps = <0>; + txen-skew-ps = <0>; + txc-skew-ps = <2600>; + rxdv-skew-ps = <0>; + rxc-skew-ps = <2000>; +}; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index d1ec0cab2de..c01acce2e8a 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -75,3 +75,11 @@ }; }; }; + +ðernet0 { + status = "okay"; +}; + +&gmac0 { + phy-mode = "gmii"; +}; -- cgit v1.2.3-70-g09d2 From 200c0a3e404beab02be83e5cbf111d26b9f6ce22 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Thu, 20 Feb 2014 06:02:35 +1000 Subject: Power: Reset: Generalize qnap-poweroff to work on Synology devices. The Synology NAS devices use a very similar mechanism to QNAP NAS devices to power off. Both send a single charactor command to a PIC, over the second serial port. However the baud rate and the command differ. Generalize the driver to support this. Signed-off-by: Ben Peddell Signed-off-by: Andrew Lunn Acked-by: Jason Cooper Cc: Anton Vorontsov Cc: Dmitry Eremin-Solenikov Cc: David Woodhouse Signed-off-by: Jason Cooper --- .../bindings/power_supply/qnap-poweroff.txt | 5 ++- drivers/power/reset/qnap-poweroff.c | 49 ++++++++++++++++------ 2 files changed, 41 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt index 0347d8350d9..af25e77c0e0 100644 --- a/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt +++ b/Documentation/devicetree/bindings/power_supply/qnap-poweroff.txt @@ -6,8 +6,11 @@ Orion5x SoCs. Sending the character 'A', at 19200 baud, tells the microcontroller to turn the power off. This driver adds a handler to pm_power_off which is called to turn the power off. +Synology NAS devices use a similar scheme, but a different baud rate, +9600, and a different character, '1'. + Required Properties: -- compatible: Should be "qnap,power-off" +- compatible: Should be "qnap,power-off" or "synology,power-off" - reg: Address and length of the register set for UART1 - clocks: tclk clock diff --git a/drivers/power/reset/qnap-poweroff.c b/drivers/power/reset/qnap-poweroff.c index 37f56f7ee92..a75db7f8a92 100644 --- a/drivers/power/reset/qnap-poweroff.c +++ b/drivers/power/reset/qnap-poweroff.c @@ -1,5 +1,5 @@ /* - * QNAP Turbo NAS Board power off + * QNAP Turbo NAS Board power off. Can also be used on Synology devices. * * Copyright (C) 2012 Andrew Lunn * @@ -25,17 +25,43 @@ #define UART1_REG(x) (base + ((UART_##x) << 2)) +struct power_off_cfg { + u32 baud; + char cmd; +}; + +static const struct power_off_cfg qnap_power_off_cfg = { + .baud = 19200, + .cmd = 'A', +}; + +static const struct power_off_cfg synology_power_off_cfg = { + .baud = 9600, + .cmd = '1', +}; + +static const struct of_device_id qnap_power_off_of_match_table[] = { + { .compatible = "qnap,power-off", + .data = &qnap_power_off_cfg, + }, + { .compatible = "synology,power-off", + .data = &synology_power_off_cfg, + }, + {} +}; +MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); + static void __iomem *base; static unsigned long tclk; +static const struct power_off_cfg *cfg; static void qnap_power_off(void) { - /* 19200 baud divisor */ - const unsigned divisor = ((tclk + (8 * 19200)) / (16 * 19200)); + const unsigned divisor = ((tclk + (8 * cfg->baud)) / (16 * cfg->baud)); pr_err("%s: triggering power-off...\n", __func__); - /* hijack UART1 and reset into sane state (19200,8n1) */ + /* hijack UART1 and reset into sane state */ writel(0x83, UART1_REG(LCR)); writel(divisor & 0xff, UART1_REG(DLL)); writel((divisor >> 8) & 0xff, UART1_REG(DLM)); @@ -44,16 +70,21 @@ static void qnap_power_off(void) writel(0x00, UART1_REG(FCR)); writel(0x00, UART1_REG(MCR)); - /* send the power-off command 'A' to PIC */ - writel('A', UART1_REG(TX)); + /* send the power-off command to PIC */ + writel(cfg->cmd, UART1_REG(TX)); } static int qnap_power_off_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; struct resource *res; struct clk *clk; char symname[KSYM_NAME_LEN]; + const struct of_device_id *match = + of_match_node(qnap_power_off_of_match_table, np); + cfg = match->data; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "Missing resource"); @@ -94,12 +125,6 @@ static int qnap_power_off_remove(struct platform_device *pdev) return 0; } -static const struct of_device_id qnap_power_off_of_match_table[] = { - { .compatible = "qnap,power-off", }, - {} -}; -MODULE_DEVICE_TABLE(of, qnap_power_off_of_match_table); - static struct platform_driver qnap_power_off_driver = { .probe = qnap_power_off_probe, .remove = qnap_power_off_remove, -- cgit v1.2.3-70-g09d2 From 9b931361ff0971d2639b1366f8b468c687fa942f Mon Sep 17 00:00:00 2001 From: Dinh Nguyen Date: Mon, 17 Feb 2014 20:31:02 -0600 Subject: dts: socfpga: Add support for SD/MMC on the SOCFPGA platform Introduce "altr,socfpga-dw-mshc" to enable Altera's SOCFPGA platform specific implementation of the dw_mmc driver. Also add the "syscon" binding to the "altr,sys-mgr" node. The clock driver can use the syscon driver to toggle the register for the SD/MMC clock phase shift settings. Finally, fix an indentation error for the sysmgr node. Signed-off-by: Dinh Nguyen Acked-by: Steffen Trumtrar Tested-by: Steffen Trumtrar Signed-off-by: Chris Ball --- .../devicetree/bindings/mmc/socfpga-dw-mshc.txt | 23 ++++++++++++++++++++++ arch/arm/boot/dts/socfpga.dtsi | 17 +++++++++++++--- arch/arm/boot/dts/socfpga_arria5.dtsi | 11 +++++++++++ arch/arm/boot/dts/socfpga_cyclone5.dtsi | 11 +++++++++++ arch/arm/boot/dts/socfpga_vt.dts | 11 +++++++++++ 5 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt new file mode 100644 index 00000000000..4897bea7e3f --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/socfpga-dw-mshc.txt @@ -0,0 +1,23 @@ +* Altera SOCFPGA specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +The Synopsys designware mobile storage host controller is used to interface +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents +differences between the core Synopsys dw mshc controller properties described +by synopsys-dw-mshc.txt and the properties used by the Altera SOCFPGA specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be + - "altr,socfpga-dw-mshc": for Altera's SOCFPGA platform + +Example: + + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 129 4>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 3ce09e39dc9..d2ff3d5d83e 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -499,6 +499,17 @@ arm,data-latency = <2 1 1>; }; + mmc: dwmmc0@ff704000 { + compatible = "altr,socfpga-dw-mshc"; + reg = <0xff704000 0x1000>; + interrupts = <0 139 4>; + fifo-depth = <0x400>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&l4_mp_clk>, <&sdmmc_clk>; + clock-names = "biu", "ciu"; + }; + /* Local timer */ timer@fffec600 { compatible = "arm,cortex-a9-twd-timer"; @@ -553,8 +564,8 @@ }; sysmgr@ffd08000 { - compatible = "altr,sys-mgr"; - reg = <0xffd08000 0x4000>; - }; + compatible = "altr,sys-mgr", "syscon"; + reg = <0xffd08000 0x4000>; + }; }; }; diff --git a/arch/arm/boot/dts/socfpga_arria5.dtsi b/arch/arm/boot/dts/socfpga_arria5.dtsi index a85b4043f88..6c87b7070ca 100644 --- a/arch/arm/boot/dts/socfpga_arria5.dtsi +++ b/arch/arm/boot/dts/socfpga_arria5.dtsi @@ -27,6 +27,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + serial0@ffc02000 { clock-frequency = <100000000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi index a8716f6dbe2..ca41b0ebf46 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi +++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi @@ -28,6 +28,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff702000 { phy-mode = "rgmii"; phy-addr = <0xffffffff>; /* probe for phy addr */ diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index c01acce2e8a..91f6ccf714e 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -41,6 +41,17 @@ }; }; + dwmmc0@ff704000 { + num-slots = <1>; + supports-highspeed; + broken-cd; + + slot@0 { + reg = <0>; + bus-width = <4>; + }; + }; + ethernet@ff700000 { phy-mode = "gmii"; status = "okay"; -- cgit v1.2.3-70-g09d2 From b80a6373d6cf7cbd22498409cef7883d7f8209c4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 27 Mar 2014 01:26:00 +0100 Subject: Revert "dts: socfpga: Add DTS entry for adding the stmmac glue layer for stmmac." This reverts commit 7e0b4cd06201ee9dbdf2d13bfd7b8a021b414e42. The binding changes need to be done differently as well, let's take them through netdev, and merge the dts changes in a new patch here. Signed-off-by: Arnd Bergmann --- .../devicetree/bindings/net/socfpga-dwmac.txt | 35 ---------------- arch/arm/boot/dts/socfpga.dtsi | 49 +++++++--------------- arch/arm/boot/dts/socfpga_arria5_socdk.dts | 24 ----------- arch/arm/boot/dts/socfpga_cyclone5_socdk.dts | 17 -------- arch/arm/boot/dts/socfpga_cyclone5_sockit.dts | 22 +--------- arch/arm/boot/dts/socfpga_vt.dts | 8 ---- 6 files changed, 17 insertions(+), 138 deletions(-) delete mode 100644 Documentation/devicetree/bindings/net/socfpga-dwmac.txt (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt b/Documentation/devicetree/bindings/net/socfpga-dwmac.txt deleted file mode 100644 index d53d3765b2c..00000000000 --- a/Documentation/devicetree/bindings/net/socfpga-dwmac.txt +++ /dev/null @@ -1,35 +0,0 @@ -Altera SOCFPGA SoC DWMAC controller - -The device node has following properties. - -Required properties: - - compatible : Should contain "altr,socfpga-stmmac" - - altr,sysmgr-syscon : Should be the phandle to the system manager node that - encompasses the glue register, and the register offset. - -Sub-nodes: -The dwmac core should be added as subnode to SOCFPGA dwmac glue. -- dwmac : The binding details of dwmac can be found in - Documentation/devicetree/bindings/net/stmmac.txt - -Example: - -ethernet0: ethernet0 { - #address-cells = <1>; - #size-cells = <1>; - - compatible = "altr,socfpga-stmmac"; - altr,sysmgr-syscon = <&sysmgr 0x60>; - status = "disabled"; - ranges; - - gmac0: gmac0@ff700000 { - compatible = "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff700000 0x2000>; - interrupts = <0 115 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac0_clk>; - clock-names = "stmmaceth"; - }; -}; diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi index 404553c97f3..74cceae8fde 100644 --- a/arch/arm/boot/dts/socfpga.dtsi +++ b/arch/arm/boot/dts/socfpga.dtsi @@ -450,43 +450,26 @@ }; }; - ethernet0: ethernet0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "altr,socfpga-stmmac"; - altr,sysmgr-syscon = <&sysmgr 0x60>; + gmac0: ethernet@ff700000 { + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff700000 0x2000>; + interrupts = <0 115 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac0_clk>; + clock-names = "stmmaceth"; status = "disabled"; - ranges; - - gmac0: gmac0@ff700000 { - compatible = "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff700000 0x2000>; - interrupts = <0 115 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac0_clk>; - clock-names = "stmmaceth"; - }; }; - ethernet1: ethernet1 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "altr,socfpga-stmmac"; - altr,sysmgr-syscon = <&sysmgr 0x60>; + gmac1: ethernet@ff702000 { + compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac"; + reg = <0xff702000 0x2000>; + interrupts = <0 120 4>; + interrupt-names = "macirq"; + mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ + clocks = <&emac1_clk>; + clock-names = "stmmaceth"; status = "disabled"; - ranges; - - gmac1: gmac1@ff702000 { - device_type = "network"; - compatible = "snps,dwmac-3.70a", "snps,dwmac"; - reg = <0xff702000 0x2000>; - interrupts = <0 120 4>; - interrupt-names = "macirq"; - mac-address = [00 00 00 00 00 00];/* Filled in by U-Boot */ - clocks = <&emac1_clk>; - clock-names = "stmmaceth"; - }; }; L2: l2-cache@fffef000 { diff --git a/arch/arm/boot/dts/socfpga_arria5_socdk.dts b/arch/arm/boot/dts/socfpga_arria5_socdk.dts index 2d6b38ba937..5beffb2265f 100644 --- a/arch/arm/boot/dts/socfpga_arria5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_arria5_socdk.dts @@ -37,28 +37,4 @@ */ ethernet0 = &gmac1; }; - - aliases { - /* this allow the ethaddr uboot environmnet variable contents - * to be added to the gmac1 device tree blob. - */ - ethernet0 = &gmac1; - }; -}; - -ðernet1 { - status = "okay"; -}; - -&gmac1 { - phy-mode = "rgmii"; - - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txen-skew-ps = <0>; - txc-skew-ps = <2600>; - rxdv-skew-ps = <0>; - rxc-skew-ps = <2000>; }; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts index 26c63a07f8b..2ee52ab8cab 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_socdk.dts @@ -38,20 +38,3 @@ ethernet0 = &gmac1; }; }; - -ðernet1 { - status = "okay"; -}; - -&gmac1 { - phy-mode = "rgmii"; - - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txen-skew-ps = <0>; - txc-skew-ps = <2600>; - rxdv-skew-ps = <0>; - rxc-skew-ps = <2000>; -}; diff --git a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts index 469bb5cac88..50b99a2c12a 100644 --- a/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts +++ b/arch/arm/boot/dts/socfpga_cyclone5_sockit.dts @@ -30,28 +30,8 @@ device_type = "memory"; reg = <0x0 0x40000000>; /* 1GB */ }; - - aliases { - /* this allow the ethaddr uboot environmnet variable contents - * to be added to the gmac1 device tree blob. - */ - ethernet0 = &gmac1; - }; -}; - -ðernet1 { - status = "okay"; }; &gmac1 { - phy-mode = "rgmii"; - - rxd0-skew-ps = <0>; - rxd1-skew-ps = <0>; - rxd2-skew-ps = <0>; - rxd3-skew-ps = <0>; - txen-skew-ps = <0>; - txc-skew-ps = <2600>; - rxdv-skew-ps = <0>; - rxc-skew-ps = <2000>; + status = "okay"; }; diff --git a/arch/arm/boot/dts/socfpga_vt.dts b/arch/arm/boot/dts/socfpga_vt.dts index 91f6ccf714e..222313f5420 100644 --- a/arch/arm/boot/dts/socfpga_vt.dts +++ b/arch/arm/boot/dts/socfpga_vt.dts @@ -86,11 +86,3 @@ }; }; }; - -ðernet0 { - status = "okay"; -}; - -&gmac0 { - phy-mode = "gmii"; -}; -- cgit v1.2.3-70-g09d2