The 98DX3236, 98DX3336 and 98DX4251 are a set of switch ASICs with integrated CPUs. They CPU block is common within these product lines and (as far as I can tell/have been told) is based on the Armada XP. There are a few differences due to the fact they have to squeeze the CPU into the same package as the switch. Chris Packham (4): clk: mvebu: support for 98DX3236 SoC Changes in v2: - Update devicetree binding documentation for new compatible string Changes in v3: - Add 98dx3236 support to mvebu/clk-corediv.c rather than creating a new driver. - Document mv98dx3236-corediv-clock binding arm: mvebu: support for SMP on 98DX3336 SoC Changes in v2: - Document new enable-method value - Correct some references from 98DX4521 to 98DX3236 Changes in v3: - Simplify mv98dx3236_resume_init by using of_io_request_and_map() arm: mvebu: Add device tree for 98DX3236 SoCs Changes in v2: - Update devicetree binding documentation to reflect that 98DX3336 and 984251 are supersets of 98DX3236. - disable crypto block - disable sdio for 98DX3236, enable for 98DX4251 Changes in v3: - fix typo 4521 -> 4251 - document prestera bindings - rework corediv-clock binding - add label to packet processor node - add new compativle string for DFX server arm: mvebu: Add device tree for db-dxbc2 and db-xc3-24g4xg boards Changes in v2/v3: - none Kalyan Kinthada (1): pinctrl: mvebu: pinctrl driver for 98DX3236 SoC Changes in v2: - include sdio support for the 98DX4251 Changes in v3: - None Documentation/devicetree/bindings/arm/cpus.txt | 1 + .../bindings/arm/marvell/98dx3236-resume-ctrl.txt | 18 ++ .../devicetree/bindings/arm/marvell/98dx3236.txt | 23 ++ .../bindings/clock/mvebu-corediv-clock.txt | 1 + .../devicetree/bindings/clock/mvebu-cpu-clock.txt | 1 + .../devicetree/bindings/net/marvell,prestera.txt | 50 ++++ .../pinctrl/marvell,armada-98dx3236-pinctrl.txt | 46 ++++ arch/arm/boot/dts/armada-xp-98dx3236.dtsi | 254 +++++++++++++++++++++ arch/arm/boot/dts/armada-xp-98dx3336.dtsi | 76 ++++++ arch/arm/boot/dts/armada-xp-98dx4251.dtsi | 90 ++++++++ arch/arm/boot/dts/db-dxbc2.dts | 159 +++++++++++++ arch/arm/boot/dts/db-xc3-24g4xg.dts | 155 +++++++++++++ arch/arm/mach-mvebu/Makefile | 1 + arch/arm/mach-mvebu/common.h | 1 + arch/arm/mach-mvebu/platsmp.c | 43 ++++ arch/arm/mach-mvebu/pmsu-98dx3236.c | 52 +++++ drivers/clk/mvebu/armada-xp.c | 42 ++++ drivers/clk/mvebu/clk-corediv.c | 23 ++ drivers/clk/mvebu/clk-cpu.c | 31 ++- drivers/pinctrl/mvebu/pinctrl-armada-xp.c | 155 +++++++++++++ 20 files changed, 1220 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt create mode 100644 Documentation/devicetree/bindings/arm/marvell/98dx3236.txt create mode 100644 Documentation/devicetree/bindings/net/marvell,prestera.txt create mode 100644 Documentation/devicetree/bindings/pinctrl/marvell,armada-98dx3236-pinctrl.txt create mode 100644 arch/arm/boot/dts/armada-xp-98dx3236.dtsi create mode 100644 arch/arm/boot/dts/armada-xp-98dx3336.dtsi create mode 100644 arch/arm/boot/dts/armada-xp-98dx4251.dtsi create mode 100644 arch/arm/boot/dts/db-dxbc2.dts create mode 100644 arch/arm/boot/dts/db-xc3-24g4xg.dts create mode 100644 arch/arm/mach-mvebu/pmsu-98dx3236.c Interdiff to v2: diff --git a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt index 520562a7dc2a..c7b4e3a6b2c6 100644 --- a/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt +++ b/Documentation/devicetree/bindings/clock/mvebu-corediv-clock.txt @@ -7,6 +7,7 @@ Required properties: - compatible : must be "marvell,armada-370-corediv-clock", "marvell,armada-375-corediv-clock", "marvell,armada-380-corediv-clock", + "marvell,mv98dx3236-corediv-clock", - reg : must be the register address of Core Divider control register - #clock-cells : from common clock binding; shall be set to 1 diff --git a/Documentation/devicetree/bindings/net/marvell,prestera.txt b/Documentation/devicetree/bindings/net/marvell,prestera.txt new file mode 100644 index 000000000000..5fbab29718e8 --- /dev/null +++ b/Documentation/devicetree/bindings/net/marvell,prestera.txt @@ -0,0 +1,50 @@ +Marvell Prestera Switch Chip bindings +------------------------------------- + +Required properties: +- compatible: one of the following + "marvell,prestera-98dx3236", + "marvell,prestera-98dx3336", + "marvell,prestera-98dx4251", +- reg: address and length of the register set for the device. +- interrupts: interrupt for the device + +Optional properties: +- dfx: phandle reference to the "DFX Server" node + +Example: + +switch { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0x03, 0x00) 0 0x100000>; + + packet-processor@0 { + compatible = "marvell,prestera-98dx3236"; + reg = <0 0x4000000>; + interrupts = <33>, <34>, <35>; + dfx = <&dfx>; + }; +}; + +DFX Server bindings +------------------- + +Required properties: +- compatible: must be "marvell,dfx-server" +- reg: address and length of the register set for the device. + +Example: + +dfx-registers { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; + + dfx: dfx@0 { + compatible = "marvell,dfx-server"; + reg = <0 0x100000>; + }; +}; diff --git a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi index 61bd3acc5cfe..4b7b2fe3b682 100644 --- a/arch/arm/boot/dts/armada-xp-98dx3236.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx3236.dtsi @@ -126,12 +126,7 @@ }; corediv-clock@18740 { - compatible = "marvell,mv98dx3236-corediv-clock"; - reg = <0xf8268 0xc>; - base = <&dfx>; - #clock-cells = <1>; - clocks = <&mainpll>; - clock-output-names = "nand"; + status = "disabled"; }; xor@60900 { @@ -194,6 +189,10 @@ #interrupt-cells = <2>; interrupts = <87>; }; + + nand: nand@d0000 { + clocks = <&dfx_coredivclk 0>; + }; }; dfx-registers { @@ -202,8 +201,16 @@ #size-cells = <1>; ranges = <0 MBUS_ID(0x08, 0x00) 0 0x100000>; + dfx_coredivclk: corediv-clock@f8268 { + compatible = "marvell,mv98dx3236-corediv-clock"; + reg = <0xf8268 0xc>; + #clock-cells = <1>; + clocks = <&mainpll>; + clock-output-names = "nand"; + }; + dfx: dfx@0 { - compatible = "simple-bus"; + compatible = "marvell,dfx-server"; reg = <0 0x100000>; }; }; @@ -214,7 +221,7 @@ #size-cells = <1>; ranges = <0 MBUS_ID(0x03, 0x00) 0 0x100000>; - packet-processor@0 { + pp0: packet-processor@0 { compatible = "marvell,prestera-98dx3236"; reg = <0 0x4000000>; interrupts = <33>, <34>, <35>; diff --git a/arch/arm/boot/dts/armada-xp-98dx3336.dtsi b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi index 9c9aa565fd82..a9b0f47f8df9 100644 --- a/arch/arm/boot/dts/armada-xp-98dx3336.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx3336.dtsi @@ -68,11 +68,9 @@ reg = <0x20980 0x10>; }; }; - - switch { - packet-processor@0 { - compatible = "marvell,prestera-98dx3336"; - }; - }; }; }; + +&pp0 { + compatible = "marvell,prestera-98dx3336"; +}; diff --git a/arch/arm/boot/dts/armada-xp-98dx4251.dtsi b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi index 5f7edc23d5ae..446e6e65ec59 100644 --- a/arch/arm/boot/dts/armada-xp-98dx4251.dtsi +++ b/arch/arm/boot/dts/armada-xp-98dx4251.dtsi @@ -68,12 +68,6 @@ reg = <0x20980 0x10>; }; }; - - switch { - packet-processor@0 { - compatible = "marvell,prestera-98dx4521"; - }; - }; }; }; @@ -90,3 +84,7 @@ marvell,function = "sd0"; }; }; + +&pp0 { + compatible = "marvell,prestera-98dx4251"; +}; diff --git a/arch/arm/mach-mvebu/pmsu-98dx3236.c b/arch/arm/mach-mvebu/pmsu-98dx3236.c index 87ca42ef40c7..1052674dd439 100644 --- a/arch/arm/mach-mvebu/pmsu-98dx3236.c +++ b/arch/arm/mach-mvebu/pmsu-98dx3236.c @@ -31,39 +31,22 @@ void mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr) static int __init mv98dx3236_resume_init(void) { struct device_node *np; - struct resource res; - int ret = 0; + void __iomem *base; np = of_find_matching_node(NULL, of_mv98dx3236_resume_table); if (!np) return 0; - pr_info("Initializing 98DX3236 Resume\n"); - - if (of_address_to_resource(np, 0, &res)) { - pr_err("unable to get resource\n"); - ret = -ENOENT; - goto out; - } - - if (!request_mem_region(res.start, resource_size(&res), - np->full_name)) { - pr_err("unable to request region\n"); - ret = -EBUSY; - goto out; - } - - mv98dx3236_resume_base = ioremap(res.start, resource_size(&res)); - if (!mv98dx3236_resume_base) { + base = of_io_request_and_map(np, 0, of_node_full_name(np)); + if (IS_ERR(base)) { pr_err("unable to map registers\n"); - release_mem_region(res.start, resource_size(&res)); - ret = -ENOMEM; - goto out; + of_node_put(np); + return PTR_ERR(mv98dx3236_resume_base); } -out: + mv98dx3236_resume_base = base; of_node_put(np); - return ret; + return 0; } early_initcall(mv98dx3236_resume_init); diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile index 6a3681e3d6db..d9ae97fb43c4 100644 --- a/drivers/clk/mvebu/Makefile +++ b/drivers/clk/mvebu/Makefile @@ -9,7 +9,7 @@ obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-periph.o -obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o mv98dx3236-corediv.o +obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o diff --git a/drivers/clk/mvebu/clk-corediv.c b/drivers/clk/mvebu/clk-corediv.c index d1e5863d3375..8491979f4096 100644 --- a/drivers/clk/mvebu/clk-corediv.c +++ b/drivers/clk/mvebu/clk-corediv.c @@ -71,6 +71,10 @@ static const struct clk_corediv_desc mvebu_corediv_desc[] = { { .mask = 0x3f, .offset = 8, .fieldbit = 1 }, /* NAND clock */ }; +static const struct clk_corediv_desc mv98dx3236_corediv_desc[] = { + { .mask = 0x0f, .offset = 6, .fieldbit = 26 }, /* NAND clock */ +}; + #define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) static int clk_corediv_is_enabled(struct clk_hw *hwclk) @@ -232,6 +236,18 @@ static const struct clk_corediv_soc_desc armada375_corediv_soc = { .ratio_offset = 0x4, }; +static const struct clk_corediv_soc_desc mv98dx3236_corediv_soc = { + .descs = mv98dx3236_corediv_desc, + .ndescs = ARRAY_SIZE(mv98dx3236_corediv_desc), + .ops = { + .recalc_rate = clk_corediv_recalc_rate, + .round_rate = clk_corediv_round_rate, + .set_rate = clk_corediv_set_rate, + }, + .ratio_reload = BIT(10), + .ratio_offset = 0x8, +}; + static void __init mvebu_corediv_clk_init(struct device_node *node, const struct clk_corediv_soc_desc *soc_desc) @@ -313,3 +329,10 @@ static void __init armada380_corediv_clk_init(struct device_node *node) } CLK_OF_DECLARE(armada380_corediv_clk, "marvell,armada-380-corediv-clock", armada380_corediv_clk_init); + +static void __init mv98dx3236_corediv_clk_init(struct device_node *node) +{ + return mvebu_corediv_clk_init(node, &mv98dx3236_corediv_soc); +} +CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock", + mv98dx3236_corediv_clk_init); diff --git a/drivers/clk/mvebu/clk-cpu.c b/drivers/clk/mvebu/clk-cpu.c index 29f295e7a36b..3b8f0e14fa01 100644 --- a/drivers/clk/mvebu/clk-cpu.c +++ b/drivers/clk/mvebu/clk-cpu.c @@ -254,7 +254,7 @@ static void __init of_cpu_clk_setup(struct device_node *node) } CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock", - of_cpu_clk_setup); + of_cpu_clk_setup); /* Define the clock and operations for the mv98dx3236 - it cannot * perform * any operations. diff --git a/drivers/clk/mvebu/mv98dx3236-corediv.c b/drivers/clk/mvebu/mv98dx3236-corediv.c deleted file mode 100644 index 3060764a8e5d..000000000000 --- a/drivers/clk/mvebu/mv98dx3236-corediv.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * MV98DX3236 Core divider clock - * - * Copyright (C) 2015 Allied Telesis Labs - * - * Based on armada-xp-corediv.c - * Copyright (C) 2015 Marvell - * - * John Thompson <john.thompson@xxxxxxxxxxxxxxxxxxx> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ -#include <linux/kernel.h> -#include <linux/clk-provider.h> -#include <linux/of_address.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include "common.h" - -#define CORE_CLK_DIV_RATIO_MASK 0xff - -#define CLK_DIV_RATIO_NAND_MASK 0x0f -#define CLK_DIV_RATIO_NAND_OFFSET 6 -#define CLK_DIV_RATIO_NAND_FORCE_RELOAD_BIT 26 - -#define RATIO_RELOAD_BIT BIT(10) -#define RATIO_REG_OFFSET 0x08 - -/* - * This structure represents one core divider clock for the clock - * framework, and is dynamically allocated for each core divider clock - * existing in the current SoC. - */ -struct clk_corediv { - struct clk_hw hw; - void __iomem *reg; - spinlock_t lock; -}; - -static struct clk_onecell_data clk_data; - - -#define to_corediv_clk(p) container_of(p, struct clk_corediv, hw) - -static int mv98dx3236_corediv_is_enabled(struct clk_hw *hwclk) -{ - /* Core divider is always active */ - return 1; -} - -static int mv98dx3236_corediv_enable(struct clk_hw *hwclk) -{ - /* always succeeds */ - return 0; -} - -static void mv98dx3236_corediv_disable(struct clk_hw *hwclk) -{ - /* can't be disabled so is left alone */ -} - -static unsigned long mv98dx3236_corediv_recalc_rate(struct clk_hw *hwclk, - unsigned long parent_rate) -{ - struct clk_corediv *corediv = to_corediv_clk(hwclk); - u32 reg, div; - - reg = readl(corediv->reg + RATIO_REG_OFFSET); - div = (reg >> CLK_DIV_RATIO_NAND_OFFSET) & CLK_DIV_RATIO_NAND_MASK; - return parent_rate / div; -} - -static long mv98dx3236_corediv_round_rate(struct clk_hw *hwclk, - unsigned long rate, unsigned long *parent_rate) -{ - /* Valid ratio are 1:4, 1:5, 1:6 and 1:8 */ - u32 div; - - div = *parent_rate / rate; - if (div < 4) - div = 4; - else if (div > 6) - div = 8; - - return *parent_rate / div; -} - -static int mv98dx3236_corediv_set_rate(struct clk_hw *hwclk, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_corediv *corediv = to_corediv_clk(hwclk); - unsigned long flags = 0; - u32 reg, div; - - div = parent_rate / rate; - - spin_lock_irqsave(&corediv->lock, flags); - - /* Write new divider to the divider ratio register */ - reg = readl(corediv->reg + RATIO_REG_OFFSET); - reg &= ~(CLK_DIV_RATIO_NAND_MASK << CLK_DIV_RATIO_NAND_OFFSET); - reg |= (div & CLK_DIV_RATIO_NAND_MASK) << CLK_DIV_RATIO_NAND_OFFSET; - writel(reg, corediv->reg + RATIO_REG_OFFSET); - - /* Set reload-force for this clock */ - reg = readl(corediv->reg) | BIT(CLK_DIV_RATIO_NAND_FORCE_RELOAD_BIT); - writel(reg, corediv->reg); - - /* Now trigger the clock update */ - reg = readl(corediv->reg + RATIO_REG_OFFSET) | RATIO_RELOAD_BIT; - writel(reg, corediv->reg + RATIO_REG_OFFSET); - - /* - * Wait for clocks to settle down, and then clear all the - * ratios request and the reload request. - */ - udelay(1000); - reg &= ~(CORE_CLK_DIV_RATIO_MASK | RATIO_RELOAD_BIT); - writel(reg, corediv->reg + RATIO_REG_OFFSET); - udelay(1000); - - spin_unlock_irqrestore(&corediv->lock, flags); - - return 0; -} - -static const struct clk_ops ops = { - .enable = mv98dx3236_corediv_enable, - .disable = mv98dx3236_corediv_disable, - .is_enabled = mv98dx3236_corediv_is_enabled, - .recalc_rate = mv98dx3236_corediv_recalc_rate, - .round_rate = mv98dx3236_corediv_round_rate, - .set_rate = mv98dx3236_corediv_set_rate, -}; - -static void __init mv98dx3236_corediv_clk_init(struct device_node *node) -{ - struct clk_init_data init; - struct clk_corediv *corediv; - struct clk **clks; - void __iomem *base; - const __be32 *off; - const char *parent_name; - const char *clk_name; - int len; - struct device_node *dfx_node; - - dfx_node = of_parse_phandle(node, "base", 0); - if (WARN_ON(!dfx_node)) - return; - - off = of_get_property(node, "reg", &len); - if (WARN_ON(!off)) - return; - - base = of_iomap(dfx_node, 0); - if (WARN_ON(!base)) - return; - - of_node_put(dfx_node); - - parent_name = of_clk_get_parent_name(node, 0); - - clk_data.clk_num = 1; - - /* clks holds the clock array */ - clks = kcalloc(clk_data.clk_num, sizeof(struct clk *), - GFP_KERNEL); - if (WARN_ON(!clks)) - goto err_unmap; - /* corediv holds the clock specific array */ - corediv = kcalloc(clk_data.clk_num, sizeof(struct clk_corediv), - GFP_KERNEL); - if (WARN_ON(!corediv)) - goto err_free_clks; - - spin_lock_init(&corediv->lock); - - of_property_read_string_index(node, "clock-output-names", - 0, &clk_name); - - init.num_parents = 1; - init.parent_names = &parent_name; - init.name = clk_name; - init.ops = &ops; - init.flags = 0; - - corediv[0].reg = (void *)((int)base + be32_to_cpu(*off)); - corediv[0].hw.init = &init; - - clks[0] = clk_register(NULL, &corediv[0].hw); - WARN_ON(IS_ERR(clks[0])); - - clk_data.clks = clks; - of_clk_add_provider(node, of_clk_src_onecell_get, &clk_data); - return; - -err_free_clks: - kfree(clks); -err_unmap: - iounmap(base); -} - -CLK_OF_DECLARE(mv98dx3236_corediv_clk, "marvell,mv98dx3236-corediv-clock", - mv98dx3236_corediv_clk_init); -- 2.11.0.24.ge6920cf -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html