summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/mvebu/Makefile5
-rw-r--r--drivers/clk/mvebu/armada-370.c160
-rw-r--r--drivers/clk/mvebu/armada-xp.c194
-rw-r--r--drivers/clk/mvebu/common.c208
-rw-r--r--drivers/clk/mvebu/common.h70
-rw-r--r--drivers/clk/mvebu/dove.c179
-rw-r--r--drivers/clk/mvebu/kirkwood.c224
-rw-r--r--drivers/i2c/busses/i2c-omap.c4
-rw-r--r--drivers/mci/sdhci.h4
-rw-r--r--drivers/mfd/syscon.c2
-rw-r--r--drivers/mtd/ubi/cdev.c6
-rw-r--r--drivers/mtd/ubi/kapi.c93
-rw-r--r--drivers/mtd/ubi/ubi-barebox.h8
-rw-r--r--drivers/mtd/ubi/ubi.h2
-rw-r--r--drivers/net/phy/phy.c63
-rw-r--r--drivers/of/base.c155
-rw-r--r--drivers/of/fdt.c5
-rw-r--r--drivers/spi/atmel_spi.c1
-rw-r--r--drivers/video/fb.c98
20 files changed, 1388 insertions, 94 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index fb426c0bdb..a121947af0 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed.o clk-divider.o clk-fixed-factor.o \
clk-mux.o clk-gate.o clk-divider-table.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
+obj-$(CONFIG_ARCH_MVEBU) += mvebu/
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
diff --git a/drivers/clk/mvebu/Makefile b/drivers/clk/mvebu/Makefile
new file mode 100644
index 0000000000..6255a5f56d
--- /dev/null
+++ b/drivers/clk/mvebu/Makefile
@@ -0,0 +1,5 @@
+obj-y += common.o
+obj-$(CONFIG_ARCH_ARMADA_370) += armada-370.o
+obj-$(CONFIG_ARCH_ARMADA_XP) += armada-xp.o
+obj-$(CONFIG_ARCH_DOVE) += dove.o
+obj-$(CONFIG_ARCH_KIRKWOOD) += kirkwood.o
diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c
new file mode 100644
index 0000000000..d189c6ca57
--- /dev/null
+++ b/drivers/clk/mvebu/armada-370.c
@@ -0,0 +1,160 @@
+/*
+ * Marvell Armada 370 SoC clocks
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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 <common.h>
+#include <io.h>
+
+#include "common.h"
+
+/*
+ * Core Clocks
+ */
+
+#define SARL 0 /* Low part [0:31] */
+#define SARL_A370_PCLK_FREQ_OPT 11
+#define SARL_A370_PCLK_FREQ_OPT_MASK 0xF
+#define SARL_A370_FAB_FREQ_OPT 15
+#define SARL_A370_FAB_FREQ_OPT_MASK 0x1F
+#define SARL_A370_TCLK_FREQ_OPT 20
+#define SARL_A370_TCLK_FREQ_OPT_MASK 0x1
+
+enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK };
+
+static const struct coreclk_ratio a370_coreclk_ratios[] = {
+ { .id = A370_CPU_TO_NBCLK, .name = "nbclk" },
+ { .id = A370_CPU_TO_HCLK, .name = "hclk" },
+ { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" },
+};
+
+static const u32 a370_tclk_freqs[] = {
+ 16600000,
+ 20000000,
+};
+
+static u32 a370_get_tclk_freq(void __iomem *sar)
+{
+ u8 tclk_freq_select = 0;
+
+ tclk_freq_select = ((readl(sar) >> SARL_A370_TCLK_FREQ_OPT) &
+ SARL_A370_TCLK_FREQ_OPT_MASK);
+ return a370_tclk_freqs[tclk_freq_select];
+}
+
+static const u32 a370_cpu_freqs[] = {
+ 400000000,
+ 533000000,
+ 667000000,
+ 800000000,
+ 1000000000,
+ 1067000000,
+ 1200000000,
+};
+
+static u32 a370_get_cpu_freq(void __iomem *sar)
+{
+ u32 cpu_freq;
+ u8 cpu_freq_select = 0;
+
+ cpu_freq_select = ((readl(sar) >> SARL_A370_PCLK_FREQ_OPT) &
+ SARL_A370_PCLK_FREQ_OPT_MASK);
+ if (cpu_freq_select >= ARRAY_SIZE(a370_cpu_freqs)) {
+ pr_err("CPU freq select unsupported %d\n", cpu_freq_select);
+ cpu_freq = 0;
+ } else
+ cpu_freq = a370_cpu_freqs[cpu_freq_select];
+
+ return cpu_freq;
+}
+
+static const int a370_nbclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 2}, {2, 2},
+ {1, 2}, {1, 2}, {1, 1}, {2, 3},
+ {0, 1}, {1, 2}, {2, 4}, {0, 1},
+ {1, 2}, {0, 1}, {0, 1}, {2, 2},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {2, 3}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int a370_hclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 6}, {2, 3},
+ {1, 3}, {1, 4}, {1, 2}, {2, 6},
+ {0, 1}, {1, 6}, {2, 10}, {0, 1},
+ {1, 4}, {0, 1}, {0, 1}, {2, 5},
+ {0, 1}, {0, 1}, {0, 1}, {1, 2},
+ {2, 6}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int a370_dramclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 3}, {2, 3},
+ {1, 3}, {1, 2}, {1, 2}, {2, 6},
+ {0, 1}, {1, 3}, {2, 5}, {0, 1},
+ {1, 4}, {0, 1}, {0, 1}, {2, 5},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {2, 3}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static void a370_get_clk_ratio(
+ void __iomem *sar, int id, int *mult, int *div)
+{
+ u32 opt = ((readl(sar) >> SARL_A370_FAB_FREQ_OPT) &
+ SARL_A370_FAB_FREQ_OPT_MASK);
+
+ switch (id) {
+ case A370_CPU_TO_NBCLK:
+ *mult = a370_nbclk_ratios[opt][0];
+ *div = a370_nbclk_ratios[opt][1];
+ break;
+ case A370_CPU_TO_HCLK:
+ *mult = a370_hclk_ratios[opt][0];
+ *div = a370_hclk_ratios[opt][1];
+ break;
+ case A370_CPU_TO_DRAMCLK:
+ *mult = a370_dramclk_ratios[opt][0];
+ *div = a370_dramclk_ratios[opt][1];
+ break;
+ }
+}
+
+const struct coreclk_soc_desc armada_370_coreclks = {
+ .get_tclk_freq = a370_get_tclk_freq,
+ .get_cpu_freq = a370_get_cpu_freq,
+ .get_clk_ratio = a370_get_clk_ratio,
+ .ratios = a370_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(a370_coreclk_ratios),
+};
+
+/*
+ * Clock Gating Control
+ */
+
+const struct clk_gating_soc_desc armada_370_gating_desc[] = {
+ { "audio", NULL, 0 },
+ { "pex0_en", NULL, 1 },
+ { "pex1_en", NULL, 2 },
+ { "ge1", NULL, 3 },
+ { "ge0", NULL, 4 },
+ { "pex0", "pex0_en", 5 },
+ { "pex1", "pex1_en", 9 },
+ { "sata0", NULL, 15 },
+ { "sdio", NULL, 17 },
+ { "tdm", NULL, 25 },
+ { "ddr", NULL, 28 },
+ { "sata1", NULL, 30 },
+ { }
+};
diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c
new file mode 100644
index 0000000000..ffe4f2736d
--- /dev/null
+++ b/drivers/clk/mvebu/armada-xp.c
@@ -0,0 +1,194 @@
+/*
+ * Marvell Armada XP SoC clocks
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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 <common.h>
+#include <io.h>
+
+#include "common.h"
+
+/*
+ * Core Clocks
+ *
+ * Armada XP Sample At Reset is a 64 bit bitfiled split in two
+ * register of 32 bits
+ */
+
+#define SARL 0 /* Low part [0:31] */
+#define SARL_AXP_PCLK_FREQ_OPT 21
+#define SARL_AXP_PCLK_FREQ_OPT_MASK 0x7
+#define SARL_AXP_FAB_FREQ_OPT 24
+#define SARL_AXP_FAB_FREQ_OPT_MASK 0xF
+#define SARH 4 /* High part [32:63] */
+#define SARH_AXP_PCLK_FREQ_OPT (52-32)
+#define SARH_AXP_PCLK_FREQ_OPT_MASK 0x1
+#define SARH_AXP_PCLK_FREQ_OPT_SHIFT 3
+#define SARH_AXP_FAB_FREQ_OPT (51-32)
+#define SARH_AXP_FAB_FREQ_OPT_MASK 0x1
+#define SARH_AXP_FAB_FREQ_OPT_SHIFT 4
+
+enum { AXP_CPU_TO_NBCLK, AXP_CPU_TO_HCLK, AXP_CPU_TO_DRAMCLK };
+
+static const struct coreclk_ratio axp_coreclk_ratios[] = {
+ { .id = AXP_CPU_TO_NBCLK, .name = "nbclk" },
+ { .id = AXP_CPU_TO_HCLK, .name = "hclk" },
+ { .id = AXP_CPU_TO_DRAMCLK, .name = "dramclk" },
+};
+
+/* Armada XP TCLK frequency is fixed to 250MHz */
+static u32 axp_get_tclk_freq(void __iomem *sar)
+{
+ return 250000000;
+}
+
+static const u32 axp_cpu_freqs[] = {
+ 1000000000,
+ 1066000000,
+ 1200000000,
+ 1333000000,
+ 1500000000,
+ 1666000000,
+ 1800000000,
+ 2000000000,
+ 667000000,
+ 0,
+ 800000000,
+ 1600000000,
+};
+
+static u32 axp_get_cpu_freq(void __iomem *sar)
+{
+ u32 cpu_freq;
+ u8 cpu_freq_select = 0;
+
+ cpu_freq_select = ((readl(sar + SARL) >> SARL_AXP_PCLK_FREQ_OPT) &
+ SARL_AXP_PCLK_FREQ_OPT_MASK);
+ /*
+ * The upper bit is not contiguous to the other ones and
+ * located in the high part of the SAR registers
+ */
+ cpu_freq_select |= (((readl(sar + SARH) >> SARH_AXP_PCLK_FREQ_OPT) &
+ SARH_AXP_PCLK_FREQ_OPT_MASK) << SARH_AXP_PCLK_FREQ_OPT_SHIFT);
+ if (cpu_freq_select >= ARRAY_SIZE(axp_cpu_freqs)) {
+ pr_err("CPU freq select unsupported: %d\n", cpu_freq_select);
+ cpu_freq = 0;
+ } else
+ cpu_freq = axp_cpu_freqs[cpu_freq_select];
+
+ return cpu_freq;
+}
+
+static const int axp_nbclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 2}, {2, 2},
+ {1, 2}, {1, 2}, {1, 1}, {2, 3},
+ {0, 1}, {1, 2}, {2, 4}, {0, 1},
+ {1, 2}, {0, 1}, {0, 1}, {2, 2},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {2, 3}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int axp_hclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 6}, {2, 3},
+ {1, 3}, {1, 4}, {1, 2}, {2, 6},
+ {0, 1}, {1, 6}, {2, 10}, {0, 1},
+ {1, 4}, {0, 1}, {0, 1}, {2, 5},
+ {0, 1}, {0, 1}, {0, 1}, {1, 2},
+ {2, 6}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static const int axp_dramclk_ratios[32][2] = {
+ {0, 1}, {1, 2}, {2, 3}, {2, 3},
+ {1, 3}, {1, 2}, {1, 2}, {2, 6},
+ {0, 1}, {1, 3}, {2, 5}, {0, 1},
+ {1, 4}, {0, 1}, {0, 1}, {2, 5},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {2, 3}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {1, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+};
+
+static void axp_get_clk_ratio(
+ void __iomem *sar, int id, int *mult, int *div)
+{
+ u32 opt = ((readl(sar + SARL) >> SARL_AXP_FAB_FREQ_OPT) &
+ SARL_AXP_FAB_FREQ_OPT_MASK);
+ /*
+ * The upper bit is not contiguous to the other ones and
+ * located in the high part of the SAR registers
+ */
+ opt |= (((readl(sar + SARH) >> SARH_AXP_FAB_FREQ_OPT) &
+ SARH_AXP_FAB_FREQ_OPT_MASK) << SARH_AXP_FAB_FREQ_OPT_SHIFT);
+
+ switch (id) {
+ case AXP_CPU_TO_NBCLK:
+ *mult = axp_nbclk_ratios[opt][0];
+ *div = axp_nbclk_ratios[opt][1];
+ break;
+ case AXP_CPU_TO_HCLK:
+ *mult = axp_hclk_ratios[opt][0];
+ *div = axp_hclk_ratios[opt][1];
+ break;
+ case AXP_CPU_TO_DRAMCLK:
+ *mult = axp_dramclk_ratios[opt][0];
+ *div = axp_dramclk_ratios[opt][1];
+ break;
+ }
+}
+
+const struct coreclk_soc_desc armada_xp_coreclks = {
+ .get_tclk_freq = axp_get_tclk_freq,
+ .get_cpu_freq = axp_get_cpu_freq,
+ .get_clk_ratio = axp_get_clk_ratio,
+ .ratios = axp_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(axp_coreclk_ratios),
+};
+
+/*
+ * Clock Gating Control
+ */
+
+const struct clk_gating_soc_desc armada_xp_gating_desc[] = {
+ { "audio", NULL, 0 },
+ { "ge3", NULL, 1 },
+ { "ge2", NULL, 2 },
+ { "ge1", NULL, 3 },
+ { "ge0", NULL, 4 },
+ { "pex00", NULL, 5 },
+ { "pex01", NULL, 6 },
+ { "pex02", NULL, 7 },
+ { "pex03", NULL, 8 },
+ { "pex10", NULL, 9 },
+ { "pex11", NULL, 10 },
+ { "pex12", NULL, 11 },
+ { "pex13", NULL, 12 },
+ { "bp", NULL, 13 },
+ { "sata0lnk", NULL, 14 },
+ { "sata0", "sata0lnk", 15 },
+ { "lcd", NULL, 16 },
+ { "sdio", NULL, 17 },
+ { "usb0", NULL, 18 },
+ { "usb1", NULL, 19 },
+ { "usb2", NULL, 20 },
+ { "xor0", NULL, 22 },
+ { "crypto", NULL, 23 },
+ { "tdm", NULL, 25 },
+ { "pex20", NULL, 26 },
+ { "pex30", NULL, 27 },
+ { "xor1", NULL, 28 },
+ { "sata1lnk", NULL, 29 },
+ { "sata1", "sata1lnk", 30 },
+ { }
+};
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
new file mode 100644
index 0000000000..37cc1568a3
--- /dev/null
+++ b/drivers/clk/mvebu/common.c
@@ -0,0 +1,208 @@
+/*
+ * Marvell EBU SoC common clock handling
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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 <common.h>
+#include <init.h>
+#include <of.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#include "common.h"
+
+/*
+ * Core Clocks
+ */
+
+static struct clk_onecell_data clk_data;
+
+static struct of_device_id mvebu_coreclk_ids[] = {
+ { .compatible = "marvell,armada-370-core-clock",
+ .data = (u32)&armada_370_coreclks },
+ { .compatible = "marvell,armada-xp-core-clock",
+ .data = (u32)&armada_xp_coreclks },
+ { .compatible = "marvell,dove-core-clock",
+ .data = (u32)&dove_coreclks },
+ { .compatible = "marvell,kirkwood-core-clock",
+ .data = (u32)&kirkwood_coreclks },
+ { .compatible = "marvell,mv88f6180-core-clock",
+ .data = (u32)&mv88f6180_coreclks },
+ { }
+};
+
+int mvebu_coreclk_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ const struct of_device_id *match;
+ const struct coreclk_soc_desc *desc;
+ const char *tclk_name = "tclk";
+ const char *cpuclk_name = "cpuclk";
+ void __iomem *base;
+ unsigned long rate;
+ int n;
+
+ match = of_match_node(mvebu_coreclk_ids, np);
+ if (!match)
+ return -EINVAL;
+ desc = (const struct coreclk_soc_desc *)match->data;
+
+ /* Get SAR base address */
+ base = dev_request_mem_region(dev, 0);
+ if (!base)
+ return -EINVAL;
+
+ /* Allocate struct for TCLK, cpu clk, and core ratio clocks */
+ clk_data.clk_num = 2 + desc->num_ratios;
+ clk_data.clks = xzalloc(clk_data.clk_num * sizeof(struct clk *));
+
+ /* Register TCLK */
+ of_property_read_string_index(np, "clock-output-names", 0,
+ &tclk_name);
+ rate = desc->get_tclk_freq(base);
+ clk_data.clks[0] = clk_fixed(tclk_name, rate);
+ WARN_ON(IS_ERR(clk_data.clks[0]));
+
+ /* Register CPU clock */
+ of_property_read_string_index(np, "clock-output-names", 1,
+ &cpuclk_name);
+ rate = desc->get_cpu_freq(base);
+ clk_data.clks[1] = clk_fixed(cpuclk_name, rate);
+ WARN_ON(IS_ERR(clk_data.clks[1]));
+
+ /* Register fixed-factor clocks derived from CPU clock */
+ for (n = 0; n < desc->num_ratios; n++) {
+ const char *rclk_name = desc->ratios[n].name;
+ int mult, div;
+
+ of_property_read_string_index(np, "clock-output-names",
+ 2+n, &rclk_name);
+ desc->get_clk_ratio(base, desc->ratios[n].id, &mult, &div);
+ clk_data.clks[2+n] = clk_fixed_factor(rclk_name, cpuclk_name,
+ mult, div);
+ WARN_ON(IS_ERR(clk_data.clks[2+n]));
+ };
+
+ return of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+static struct driver_d mvebu_coreclk_driver = {
+ .probe = mvebu_coreclk_probe,
+ .name = "mvebu-core-clk",
+ .of_compatible = DRV_OF_COMPAT(mvebu_coreclk_ids),
+};
+
+static int mvebu_coreclk_init(void)
+{
+ return platform_driver_register(&mvebu_coreclk_driver);
+}
+core_initcall(mvebu_coreclk_init);
+
+/*
+ * Clock Gating Control
+ */
+
+struct gate {
+ struct clk *clk;
+ int bit_idx;
+};
+
+struct clk_gating_ctrl {
+ struct gate *gates;
+ int num_gates;
+};
+
+static struct clk *clk_gating_get_src(
+ struct of_phandle_args *clkspec, void *data)
+{
+ struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
+ int n;
+
+ if (clkspec->args_count < 1)
+ return ERR_PTR(-EINVAL);
+
+ for (n = 0; n < ctrl->num_gates; n++) {
+ if (clkspec->args[0] == ctrl->gates[n].bit_idx)
+ return ctrl->gates[n].clk;
+ }
+ return ERR_PTR(-ENODEV);
+}
+
+static struct of_device_id mvebu_clk_gating_ids[] = {
+ { .compatible = "marvell,armada-370-gating-clock",
+ .data = (u32)&armada_370_gating_desc },
+ { .compatible = "marvell,armada-xp-gating-clock",
+ .data = (u32)&armada_xp_gating_desc },
+ { .compatible = "marvell,dove-gating-clock",
+ .data = (u32)&dove_gating_desc },
+ { .compatible = "marvell,kirkwood-gating-clock",
+ .data = (u32)&kirkwood_gating_desc },
+ { }
+};
+
+int mvebu_clk_gating_probe(struct device_d *dev)
+{
+ struct device_node *np = dev->device_node;
+ const struct of_device_id *match;
+ const struct clk_gating_soc_desc *desc;
+ struct clk_gating_ctrl *ctrl;
+ struct gate *gate;
+ struct clk *clk;
+ void __iomem *base;
+ const char *default_parent = NULL;
+ int n;
+
+ match = of_match_node(mvebu_clk_gating_ids, np);
+ if (!match)
+ return -EINVAL;
+ desc = (const struct clk_gating_soc_desc *)match->data;
+
+ base = dev_request_mem_region(dev, 0);
+ if (!base)
+ return -EINVAL;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk))
+ return -EINVAL;
+
+ default_parent = clk->name;
+ ctrl = xzalloc(sizeof(*ctrl));
+
+ /* Count, allocate, and register clock gates */
+ for (n = 0; desc[n].name;)
+ n++;
+
+ ctrl->num_gates = n;
+ ctrl->gates = xzalloc(ctrl->num_gates * sizeof(*gate));
+
+ for (n = 0, gate = ctrl->gates; n < ctrl->num_gates; n++, gate++) {
+ const char *parent =
+ (desc[n].parent) ? desc[n].parent : default_parent;
+ gate->bit_idx = desc[n].bit_idx;
+ gate->clk = clk_gate(desc[n].name, parent,
+ base, desc[n].bit_idx);
+ WARN_ON(IS_ERR(gate->clk));
+ }
+
+ return of_clk_add_provider(np, clk_gating_get_src, ctrl);
+}
+
+static struct driver_d mvebu_clk_gating_driver = {
+ .probe = mvebu_clk_gating_probe,
+ .name = "mvebu-clk-gating",
+ .of_compatible = DRV_OF_COMPAT(mvebu_clk_gating_ids),
+};
+
+static int mvebu_clk_gating_init(void)
+{
+ return platform_driver_register(&mvebu_clk_gating_driver);
+}
+postcore_initcall(mvebu_clk_gating_init);
diff --git a/drivers/clk/mvebu/common.h b/drivers/clk/mvebu/common.h
new file mode 100644
index 0000000000..522ccdeccd
--- /dev/null
+++ b/drivers/clk/mvebu/common.h
@@ -0,0 +1,70 @@
+/*
+ * Marvell EBU SoC common clock handling
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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.
+ */
+
+#ifndef __CLK_MVEBU_COMMON_H_
+#define __CLK_MVEBU_COMMON_H_
+
+struct coreclk_ratio {
+ int id;
+ const char *name;
+};
+
+struct coreclk_soc_desc {
+ u32 (*get_tclk_freq)(void __iomem *sar);
+ u32 (*get_cpu_freq)(void __iomem *sar);
+ void (*get_clk_ratio)(void __iomem *sar, int id, int *mult, int *div);
+ const struct coreclk_ratio *ratios;
+ int num_ratios;
+};
+
+struct clk_gating_soc_desc {
+ const char *name;
+ const char *parent;
+ int bit_idx;
+};
+
+#ifdef CONFIG_ARCH_ARMADA_370
+extern const struct coreclk_soc_desc armada_370_coreclks;
+extern const struct clk_gating_soc_desc armada_370_gating_desc[];
+#else
+static const u32 armada_370_coreclks;
+static const u32 armada_370_gating_desc;
+#endif
+
+#ifdef CONFIG_ARCH_ARMADA_XP
+extern const struct coreclk_soc_desc armada_xp_coreclks;
+extern const struct clk_gating_soc_desc armada_xp_gating_desc[];
+#else
+static const u32 armada_xp_coreclks;
+static const u32 armada_xp_gating_desc;
+#endif
+
+#ifdef CONFIG_ARCH_DOVE
+extern const struct coreclk_soc_desc dove_coreclks;
+extern const struct clk_gating_soc_desc dove_gating_desc[];
+#else
+static const u32 dove_coreclks;
+static const u32 dove_gating_desc;
+#endif
+
+#ifdef CONFIG_ARCH_KIRKWOOD
+extern const struct coreclk_soc_desc kirkwood_coreclks;
+extern const struct coreclk_soc_desc mv88f6180_coreclks;
+extern const struct clk_gating_soc_desc kirkwood_gating_desc[];
+#else
+static const u32 kirkwood_coreclks;
+static const u32 mv88f6180_coreclks;
+static const u32 kirkwood_gating_desc;
+#endif
+
+#endif
diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c
new file mode 100644
index 0000000000..9bdf89a623
--- /dev/null
+++ b/drivers/clk/mvebu/dove.c
@@ -0,0 +1,179 @@
+/*
+ * Marvell Dove SoC clocks
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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 <common.h>
+#include <io.h>
+
+#include "common.h"
+
+/*
+ * Core Clocks
+ *
+ * Dove PLL sample-at-reset configuration
+ *
+ * SAR0[8:5] : CPU frequency
+ * 5 = 1000 MHz
+ * 6 = 933 MHz
+ * 7 = 933 MHz
+ * 8 = 800 MHz
+ * 9 = 800 MHz
+ * 10 = 800 MHz
+ * 11 = 1067 MHz
+ * 12 = 667 MHz
+ * 13 = 533 MHz
+ * 14 = 400 MHz
+ * 15 = 333 MHz
+ * others reserved.
+ *
+ * SAR0[11:9] : CPU to L2 Clock divider ratio
+ * 0 = (1/1) * CPU
+ * 2 = (1/2) * CPU
+ * 4 = (1/3) * CPU
+ * 6 = (1/4) * CPU
+ * others reserved.
+ *
+ * SAR0[15:12] : CPU to DDR DRAM Clock divider ratio
+ * 0 = (1/1) * CPU
+ * 2 = (1/2) * CPU
+ * 3 = (2/5) * CPU
+ * 4 = (1/3) * CPU
+ * 6 = (1/4) * CPU
+ * 8 = (1/5) * CPU
+ * 10 = (1/6) * CPU
+ * 12 = (1/7) * CPU
+ * 14 = (1/8) * CPU
+ * 15 = (1/10) * CPU
+ * others reserved.
+ *
+ * SAR0[24:23] : TCLK frequency
+ * 0 = 166 MHz
+ * 1 = 125 MHz
+ * others reserved.
+ */
+
+#define SAR_DOVE_CPU_FREQ 5
+#define SAR_DOVE_CPU_FREQ_MASK 0xf
+#define SAR_DOVE_L2_RATIO 9
+#define SAR_DOVE_L2_RATIO_MASK 0x7
+#define SAR_DOVE_DDR_RATIO 12
+#define SAR_DOVE_DDR_RATIO_MASK 0xf
+#define SAR_DOVE_TCLK_FREQ 23
+#define SAR_DOVE_TCLK_FREQ_MASK 0x3
+
+enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
+
+static const struct coreclk_ratio dove_coreclk_ratios[] = {
+ { .id = DOVE_CPU_TO_L2, .name = "l2clk", },
+ { .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
+};
+
+static const u32 dove_tclk_freqs[] = {
+ 166666667,
+ 125000000,
+ 0, 0
+};
+
+static u32 dove_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_DOVE_TCLK_FREQ) &
+ SAR_DOVE_TCLK_FREQ_MASK;
+ return dove_tclk_freqs[opt];
+}
+
+static const u32 dove_cpu_freqs[] = {
+ 0, 0, 0, 0, 0,
+ 1000000000,
+ 933333333, 933333333,
+ 800000000, 800000000, 800000000,
+ 1066666667,
+ 666666667,
+ 533333333,
+ 400000000,
+ 333333333
+};
+
+static u32 dove_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_DOVE_CPU_FREQ) &
+ SAR_DOVE_CPU_FREQ_MASK;
+ return dove_cpu_freqs[opt];
+}
+
+static const int dove_cpu_l2_ratios[8][2] = {
+ { 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
+ { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }
+};
+
+static const int dove_cpu_ddr_ratios[16][2] = {
+ { 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 },
+ { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 },
+ { 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 },
+ { 1, 7 }, { 0, 1 }, { 1, 8 }, { 1, 10 }
+};
+
+static void dove_get_clk_ratio(
+ void __iomem *sar, int id, int *mult, int *div)
+{
+ switch (id) {
+ case DOVE_CPU_TO_L2:
+ {
+ u32 opt = (readl(sar) >> SAR_DOVE_L2_RATIO) &
+ SAR_DOVE_L2_RATIO_MASK;
+ *mult = dove_cpu_l2_ratios[opt][0];
+ *div = dove_cpu_l2_ratios[opt][1];
+ break;
+ }
+ case DOVE_CPU_TO_DDR:
+ {
+ u32 opt = (readl(sar) >> SAR_DOVE_DDR_RATIO) &
+ SAR_DOVE_DDR_RATIO_MASK;
+ *mult = dove_cpu_ddr_ratios[opt][0];
+ *div = dove_cpu_ddr_ratios[opt][1];
+ break;
+ }
+ }
+}
+
+const struct coreclk_soc_desc dove_coreclks = {
+ .get_tclk_freq = dove_get_tclk_freq,
+ .get_cpu_freq = dove_get_cpu_freq,
+ .get_clk_ratio = dove_get_clk_ratio,
+ .ratios = dove_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(dove_coreclk_ratios),
+};
+
+/*
+ * Clock Gating Control
+ */
+
+const struct clk_gating_soc_desc dove_gating_desc[] = {
+ { "usb0", NULL, 0 },
+ { "usb1", NULL, 1 },
+ { "ge", "gephy", 2 },
+ { "sata", NULL, 3 },
+ { "pex0", NULL, 4 },
+ { "pex1", NULL, 5 },
+ { "sdio0", NULL, 8 },
+ { "sdio1", NULL, 9 },
+ { "nand", NULL, 10 },
+ { "camera", NULL, 11 },
+ { "i2s0", NULL, 12 },
+ { "i2s1", NULL, 13 },
+ { "crypto", NULL, 15 },
+ { "ac97", NULL, 21 },
+ { "pdma", NULL, 22 },
+ { "xor0", NULL, 23 },
+ { "xor1", NULL, 24 },
+ { "gephy", NULL, 30 },
+ { }
+};
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c
new file mode 100644
index 0000000000..5024baf18e
--- /dev/null
+++ b/drivers/clk/mvebu/kirkwood.c
@@ -0,0 +1,224 @@
+/*
+ * Marvell Kirkwood SoC clocks
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * Based on Linux Marvell MVEBU clock providers
+ * Copyright (C) 2012 Marvell
+ *
+ * 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 <common.h>
+#include <io.h>
+
+#include "common.h"
+
+/*
+ * Core Clocks
+ *
+ * Kirkwood PLL sample-at-reset configuration
+ * (6180 has different SAR layout than other Kirkwood SoCs)
+ *
+ * SAR0[4:3,22,1] : CPU frequency (6281,6292,6282)
+ * 4 = 600 MHz
+ * 6 = 800 MHz
+ * 7 = 1000 MHz
+ * 9 = 1200 MHz
+ * 12 = 1500 MHz
+ * 13 = 1600 MHz
+ * 14 = 1800 MHz
+ * 15 = 2000 MHz
+ * others reserved.
+ *
+ * SAR0[19,10:9] : CPU to L2 Clock divider ratio (6281,6292,6282)
+ * 1 = (1/2) * CPU
+ * 3 = (1/3) * CPU
+ * 5 = (1/4) * CPU
+ * others reserved.
+ *
+ * SAR0[8:5] : CPU to DDR DRAM Clock divider ratio (6281,6292,6282)
+ * 2 = (1/2) * CPU
+ * 4 = (1/3) * CPU
+ * 6 = (1/4) * CPU
+ * 7 = (2/9) * CPU
+ * 8 = (1/5) * CPU
+ * 9 = (1/6) * CPU
+ * others reserved.
+ *
+ * SAR0[4:2] : Kirkwood 6180 cpu/l2/ddr clock configuration (6180 only)
+ * 5 = [CPU = 600 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/3) * CPU]
+ * 6 = [CPU = 800 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/4) * CPU]
+ * 7 = [CPU = 1000 MHz, L2 = (1/2) * CPU, DDR = 200 MHz = (1/5) * CPU]
+ * others reserved.
+ *
+ * SAR0[21] : TCLK frequency
+ * 0 = 200 MHz
+ * 1 = 166 MHz
+ * others reserved.
+ */
+
+#define SAR_KIRKWOOD_CPU_FREQ(x) \
+ (((x & (1 << 1)) >> 1) | \
+ ((x & (1 << 22)) >> 21) | \
+ ((x & (3 << 3)) >> 1))
+#define SAR_KIRKWOOD_L2_RATIO(x) \
+ (((x & (3 << 9)) >> 9) | \
+ (((x & (1 << 19)) >> 17)))
+#define SAR_KIRKWOOD_DDR_RATIO 5
+#define SAR_KIRKWOOD_DDR_RATIO_MASK 0xf
+#define SAR_MV88F6180_CLK 2
+#define SAR_MV88F6180_CLK_MASK 0x7
+#define SAR_KIRKWOOD_TCLK_FREQ 21
+#define SAR_KIRKWOOD_TCLK_FREQ_MASK 0x1
+
+enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
+
+static const struct coreclk_ratio kirkwood_coreclk_ratios[] = {
+ { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
+ { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
+};
+
+static u32 kirkwood_get_tclk_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_KIRKWOOD_TCLK_FREQ) &
+ SAR_KIRKWOOD_TCLK_FREQ_MASK;
+ return (opt) ? 166666667 : 200000000;
+}
+
+static const u32 kirkwood_cpu_freqs[] = {
+ 0, 0, 0, 0,
+ 600000000,
+ 0,
+ 800000000,
+ 1000000000,
+ 0,
+ 1200000000,
+ 0, 0,
+ 1500000000,
+ 1600000000,
+ 1800000000,
+ 2000000000
+};
+
+static u32 kirkwood_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = SAR_KIRKWOOD_CPU_FREQ(readl(sar));
+ return kirkwood_cpu_freqs[opt];
+}
+
+static const int kirkwood_cpu_l2_ratios[8][2] = {
+ { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
+ { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
+};
+
+static const int kirkwood_cpu_ddr_ratios[16][2] = {
+ { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
+ { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
+ { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
+ { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 }
+};
+
+static void kirkwood_get_clk_ratio(
+ void __iomem *sar, int id, int *mult, int *div)
+{
+ switch (id) {
+ case KIRKWOOD_CPU_TO_L2:
+ {
+ u32 opt = SAR_KIRKWOOD_L2_RATIO(readl(sar));
+ *mult = kirkwood_cpu_l2_ratios[opt][0];
+ *div = kirkwood_cpu_l2_ratios[opt][1];
+ break;
+ }
+ case KIRKWOOD_CPU_TO_DDR:
+ {
+ u32 opt = (readl(sar) >> SAR_KIRKWOOD_DDR_RATIO) &
+ SAR_KIRKWOOD_DDR_RATIO_MASK;
+ *mult = kirkwood_cpu_ddr_ratios[opt][0];
+ *div = kirkwood_cpu_ddr_ratios[opt][1];
+ break;
+ }
+ }
+}
+
+static const u32 mv88f6180_cpu_freqs[] = {
+ 0, 0, 0, 0, 0,
+ 600000000,
+ 800000000,
+ 1000000000
+};
+
+static u32 mv88f6180_get_cpu_freq(void __iomem *sar)
+{
+ u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) & SAR_MV88F6180_CLK_MASK;
+ return mv88f6180_cpu_freqs[opt];
+}
+
+static const int mv88f6180_cpu_ddr_ratios[8][2] = {
+ { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
+ { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
+};
+
+static void mv88f6180_get_clk_ratio(
+ void __iomem *sar, int id, int *mult, int *div)
+{
+ switch (id) {
+ case KIRKWOOD_CPU_TO_L2:
+ {
+ /* mv88f6180 has a fixed 1:2 CPU-to-L2 ratio */
+ *mult = 1;
+ *div = 2;
+ break;
+ }
+ case KIRKWOOD_CPU_TO_DDR:
+ {
+ u32 opt = (readl(sar) >> SAR_MV88F6180_CLK) &
+ SAR_MV88F6180_CLK_MASK;
+ *mult = mv88f6180_cpu_ddr_ratios[opt][0];
+ *div = mv88f6180_cpu_ddr_ratios[opt][1];
+ break;
+ }
+ }
+}
+
+const struct coreclk_soc_desc kirkwood_coreclks = {
+ .get_tclk_freq = kirkwood_get_tclk_freq,
+ .get_cpu_freq = kirkwood_get_cpu_freq,
+ .get_clk_ratio = kirkwood_get_clk_ratio,
+ .ratios = kirkwood_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
+};
+
+const struct coreclk_soc_desc mv88f6180_coreclks = {
+ .get_tclk_freq = kirkwood_get_tclk_freq,
+ .get_cpu_freq = mv88f6180_get_cpu_freq,
+ .get_clk_ratio = mv88f6180_get_clk_ratio,
+ .ratios = kirkwood_coreclk_ratios,
+ .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios),
+};
+
+/*
+ * Clock Gating Control
+ */
+
+const struct clk_gating_soc_desc kirkwood_gating_desc[] = {
+ { "ge0", NULL, 0 },
+ { "pex0", NULL, 2 },
+ { "usb0", NULL, 3 },
+ { "sdio", NULL, 4 },
+ { "tsu", NULL, 5 },
+ { "runit", NULL, 7 },
+ { "xor0", NULL, 8 },
+ { "audio", NULL, 9 },
+ { "powersave", "cpuclk", 11 },
+ { "sata0", NULL, 14 },
+ { "sata1", NULL, 15 },
+ { "xor1", NULL, 16 },
+ { "crypto", NULL, 17 },
+ { "pex1", NULL, 18 },
+ { "ge1", NULL, 19 },
+ { "tdm", NULL, 20 },
+ { }
+};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index b2a74c02c8..2eb5133494 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -246,7 +246,7 @@ struct omap_i2c_driver_data {
static struct omap_i2c_driver_data omap3_data = {
.flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
OMAP_I2C_FLAG_BUS_SHIFT_2,
- .fclk_rate = 48000,
+ .fclk_rate = 96000,
.regs = (u8 *) reg_map,
};
@@ -259,7 +259,7 @@ static struct omap_i2c_driver_data omap4_data = {
static struct omap_i2c_driver_data am33xx_data = {
.flags = OMAP_I2C_FLAG_RESET_REGS_POSTIDLE |
OMAP_I2C_FLAG_BUS_SHIFT_NONE,
- .fclk_rate = 96000,
+ .fclk_rate = 48000,
.regs = (u8 *) omap4_reg_map,
};
diff --git a/drivers/mci/sdhci.h b/drivers/mci/sdhci.h
index b2d6779ef6..2c8b6f5212 100644
--- a/drivers/mci/sdhci.h
+++ b/drivers/mci/sdhci.h
@@ -37,8 +37,10 @@
#define TRANSFER_MODE_BCEN 0x00000002
#define TRANSFER_MODE_DMAEN 0x00000001
-#define IRQSTAT_DMAE 0x10000000
+#define IRQSTAT_TE 0x04000000
+#define IRQSTAT_DMAE 0x02000000
#define IRQSTAT_AC12E 0x01000000
+#define IRQSTAT_CLE 0x00800000
#define IRQSTAT_DEBE 0x00400000
#define IRQSTAT_DCE 0x00200000
#define IRQSTAT_DTOE 0x00100000
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index b628ab7c6a..52cb433a39 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -65,7 +65,7 @@ static int syscon_probe(struct device_d *dev)
syscon->base = (void __iomem *)res->start;
dev->priv = syscon;
- dev_info(dev, "map 0x%x-0x%x registered\n", res->start, res->end);
+ dev_dbg(dev, "map 0x%x-0x%x registered\n", res->start, res->end);
return 0;
}
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 3907673386..129f2e2e29 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -5,6 +5,8 @@
#include "ubi-barebox.h"
#include "ubi.h"
+LIST_HEAD(ubi_volumes_list);
+
struct ubi_volume_cdev_priv {
struct ubi_device *ubi;
struct ubi_volume *vol;
@@ -184,6 +186,8 @@ int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol)
free(cdev->name);
}
+ list_add_tail(&vol->list, &ubi_volumes_list);
+
return 0;
}
@@ -192,6 +196,8 @@ void ubi_volume_cdev_remove(struct ubi_volume *vol)
struct cdev *cdev = &vol->cdev;
struct ubi_volume_cdev_priv *priv = cdev->priv;
+ list_del(&vol->list);
+
devfs_remove(cdev);
kfree(cdev->name);
kfree(priv);
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index fca8cc9e15..31571adf0a 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -25,6 +25,82 @@
#include "ubi.h"
/**
+ * ubi_do_get_device_info - get information about UBI device.
+ * @ubi: UBI device description object
+ * @di: the information is stored here
+ *
+ * This function is the same as 'ubi_get_device_info()', but it assumes the UBI
+ * device is locked and cannot disappear.
+ */
+void ubi_do_get_device_info(struct ubi_device *ubi, struct ubi_device_info *di)
+{
+ di->ubi_num = ubi->ubi_num;
+ di->leb_size = ubi->leb_size;
+ di->leb_start = ubi->leb_start;
+ di->min_io_size = ubi->min_io_size;
+ di->max_write_size = ubi->max_write_size;
+ di->ro_mode = ubi->ro_mode;
+}
+EXPORT_SYMBOL_GPL(ubi_do_get_device_info);
+
+/**
+ * ubi_get_device_info - get information about UBI device.
+ * @ubi_num: UBI device number
+ * @di: the information is stored here
+ *
+ * This function returns %0 in case of success, %-EINVAL if the UBI device
+ * number is invalid, and %-ENODEV if there is no such UBI device.
+ */
+int ubi_get_device_info(int ubi_num, struct ubi_device_info *di)
+{
+ struct ubi_device *ubi;
+
+ if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES)
+ return -EINVAL;
+ ubi = ubi_get_device(ubi_num);
+ if (!ubi)
+ return -ENODEV;
+ ubi_do_get_device_info(ubi, di);
+ ubi_put_device(ubi);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ubi_get_device_info);
+
+/**
+ * ubi_do_get_volume_info - get information about UBI volume.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @vi: the information is stored here
+ */
+void ubi_do_get_volume_info(struct ubi_device *ubi, struct ubi_volume *vol,
+ struct ubi_volume_info *vi)
+{
+ vi->vol_id = vol->vol_id;
+ vi->ubi_num = ubi->ubi_num;
+ vi->size = vol->reserved_pebs;
+ vi->used_bytes = vol->used_bytes;
+ vi->vol_type = vol->vol_type;
+ vi->corrupted = vol->corrupted;
+ vi->upd_marker = vol->upd_marker;
+ vi->alignment = vol->alignment;
+ vi->usable_leb_size = vol->usable_leb_size;
+ vi->name_len = vol->name_len;
+ vi->name = vol->name;
+}
+
+/**
+ * ubi_get_volume_info - get information about UBI volume.
+ * @desc: volume descriptor
+ * @vi: the information is stored here
+ */
+void ubi_get_volume_info(struct ubi_volume_desc *desc,
+ struct ubi_volume_info *vi)
+{
+ ubi_do_get_volume_info(desc->vol->ubi, desc->vol, vi);
+}
+EXPORT_SYMBOL_GPL(ubi_get_volume_info);
+
+/**
* ubi_open_volume - open UBI volume.
* @ubi_num: UBI device number
* @vol_id: volume ID
@@ -189,6 +265,23 @@ struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name,
}
EXPORT_SYMBOL_GPL(ubi_open_volume_nm);
+extern struct list_head ubi_volumes_list;
+
+struct ubi_volume_desc *ubi_open_volume_cdev(struct cdev *cdev, int mode)
+{
+ struct ubi_volume *vol;
+
+ list_for_each_entry(vol, &ubi_volumes_list, list) {
+ if (cdev == &vol->cdev)
+ goto found;
+ }
+
+ return ERR_PTR(-ENOENT);
+
+found:
+ return ubi_open_volume(vol->ubi->ubi_num, vol->vol_id, mode);
+}
+
/**
* ubi_close_volume - close UBI volume.
* @desc: volume descriptor
diff --git a/drivers/mtd/ubi/ubi-barebox.h b/drivers/mtd/ubi/ubi-barebox.h
index 58c8a6239c..03069d0947 100644
--- a/drivers/mtd/ubi/ubi-barebox.h
+++ b/drivers/mtd/ubi/ubi-barebox.h
@@ -32,14 +32,6 @@
#define CONFIG_MTD_UBI_WL_THRESHOLD 4096
#define UBI_IO_DEBUG 0
-#define DUMP_PREFIX_OFFSET 0
-static inline void print_hex_dump(const char *level, const char *prefix_str,
- int prefix_type, int rowsize, int groupsize,
- const void *buf, size_t len, bool ascii)
-{
- memory_display(buf, 0, len, 4, 0);
-}
-
/* upd.c */
static inline unsigned long copy_from_user(void *dest, const void *src,
unsigned long count)
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index 11877a3199..aa2cf026ba 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -322,6 +322,8 @@ struct ubi_volume {
unsigned int updating:1;
unsigned int changing_leb:1;
unsigned int direct_writes:1;
+
+ struct list_head list;
};
/**
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 112ff13f77..db00e38bbc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -632,6 +632,69 @@ int genphy_read_status(struct phy_device *phydev)
return 0;
}
+static inline void mmd_phy_indirect(struct phy_device *phydev, int prtad,
+ int devad)
+{
+ /* Write the desired MMD Devad */
+ phy_write(phydev, MII_MMD_CTRL, devad);
+
+ /* Write the desired MMD register address */
+ phy_write(phydev, MII_MMD_DATA, prtad);
+
+ /* Select the Function : DATA with no post increment */
+ phy_write(phydev, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
+}
+
+/**
+ * phy_read_mmd_indirect - reads data from the MMD registers
+ * @phy_device: phy device
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ *
+ * Description: it reads data from the MMD registers (clause 22 to access to
+ * clause 45) of the specified phy address.
+ * To read these register we have:
+ * 1) Write reg 13 // DEVAD
+ * 2) Write reg 14 // MMD Address
+ * 3) Write reg 13 // MMD Data Command for MMD DEVAD
+ * 3) Read reg 14 // Read MMD data
+ */
+int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, int devad)
+{
+ u32 ret;
+
+ mmd_phy_indirect(phydev, prtad, devad);
+
+ /* Read the content of the MMD's selected register */
+ ret = phy_read(phydev, MII_MMD_DATA);
+
+ return ret;
+}
+
+/**
+ * phy_write_mmd_indirect - writes data to the MMD registers
+ * @phy_device: phy device
+ * @prtad: MMD Address
+ * @devad: MMD DEVAD
+ * @data: data to write in the MMD register
+ *
+ * Description: Write data from the MMD registers of the specified
+ * phy address.
+ * To write these register we have:
+ * 1) Write reg 13 // DEVAD
+ * 2) Write reg 14 // MMD Address
+ * 3) Write reg 13 // MMD Data Command for MMD DEVAD
+ * 3) Write reg 14 // Write MMD data
+ */
+void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, int devad,
+ u16 data)
+{
+ mmd_phy_indirect(phydev, prtad, devad);
+
+ /* Write the data into MMD's selected register */
+ phy_write(phydev, MII_MMD_DATA, data);
+}
+
static int genphy_config_init(struct phy_device *phydev)
{
int val;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 8af51d49ca..116dd0c96d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -241,6 +241,32 @@ const char *of_alias_get(struct device_node *np)
EXPORT_SYMBOL_GPL(of_alias_get);
/*
+ * of_find_node_by_alias - Find a node given an alias name
+ * @root: the root node of the tree. If NULL, use internal tree
+ * @alias: the alias name to find
+ */
+struct device_node *of_find_node_by_alias(struct device_node *root, const char *alias)
+{
+ struct device_node *aliasnp;
+ int ret;
+ const char *path;
+
+ if (!root)
+ root = root_node;
+
+ aliasnp = of_find_node_by_path_from(root, "/aliases");
+ if (!aliasnp)
+ return NULL;
+
+ ret = of_property_read_string(aliasnp, alias, &path);
+ if (ret)
+ return NULL;
+
+ return of_find_node_by_path_from(root, path);
+}
+EXPORT_SYMBOL_GPL(of_find_node_by_alias);
+
+/*
* of_find_node_by_phandle - Find a node given a phandle
* @handle: phandle of the node to find
*/
@@ -256,6 +282,62 @@ struct device_node *of_find_node_by_phandle(phandle phandle)
EXPORT_SYMBOL(of_find_node_by_phandle);
/*
+ * of_get_tree_max_phandle - Find the maximum phandle of a tree
+ * @root: root node of the tree to search in. If NULL use the
+ * internal tree.
+ */
+phandle of_get_tree_max_phandle(struct device_node *root)
+{
+ struct device_node *n;
+ phandle max;
+
+ if (!root)
+ root = root_node;
+
+ if (!root)
+ return 0;
+
+ max = root->phandle;
+
+ of_tree_for_each_node_from(n, root) {
+ if (n->phandle > max)
+ max = n->phandle;
+ }
+
+ return max;
+}
+EXPORT_SYMBOL(of_get_tree_max_phandle);
+
+/*
+ * of_node_create_phandle - create a phandle for a node
+ * @node: The node to create a phandle in
+ *
+ * returns the new phandle or the existing phandle if the node
+ * already has a phandle.
+ */
+phandle of_node_create_phandle(struct device_node *node)
+{
+ phandle p;
+ struct device_node *root;
+
+ if (node->phandle)
+ return node->phandle;
+
+ root = of_find_root_node(node);
+
+ p = of_get_tree_max_phandle(root) + 1;
+
+ node->phandle = p;
+
+ p = cpu_to_be32(p);
+
+ of_set_property(node, "phandle", &p, sizeof(p), 1);
+
+ return node->phandle;
+}
+EXPORT_SYMBOL(of_node_create_phandle);
+
+/*
* Find a property with a given name for a given node
* and return the value.
*/
@@ -319,6 +401,35 @@ struct device_node *of_find_node_by_name(struct device_node *from,
EXPORT_SYMBOL(of_find_node_by_name);
/**
+ * of_find_node_by_type - Find a node by its "device_type" property
+ * @from: The node to start searching from, or NULL to start searching
+ * the entire device tree. The node you pass will not be
+ * searched, only the next one will; typically, you pass
+ * what the previous call returned.
+ * @type: The type string to match against.
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_type(struct device_node *from,
+ const char *type)
+{
+ struct device_node *np;
+ const char *device_type;
+ int ret;
+
+ if (!from)
+ from = root_node;
+
+ of_tree_for_each_node_from(np, from) {
+ ret = of_property_read_string(np, "device_type", &device_type);
+ if (!ret && !of_node_cmp(device_type, type))
+ return np;
+ }
+ return NULL;
+}
+EXPORT_SYMBOL(of_find_node_by_type);
+
+/**
* of_find_compatible_node - Find a node based on type and one of the
* tokens in its "compatible" property
* @from: The node to start searching from or NULL, the node
@@ -1211,6 +1322,9 @@ struct device_node *of_find_node_by_path_from(struct device_node *from,
{
char *slash, *p, *freep;
+ if (!from)
+ from = root_node;
+
if (!from || !path || *path != '/')
return NULL;
@@ -1255,6 +1369,25 @@ struct device_node *of_find_node_by_path(const char *path)
EXPORT_SYMBOL(of_find_node_by_path);
/**
+ * of_find_node_by_path_or_alias - Find a node matching a full OF path
+ * or an alias
+ * @root: The root node. If NULL the internal tree is used
+ * @str: the full path or alias
+ *
+ * Returns a pointer to the node found or NULL.
+ */
+struct device_node *of_find_node_by_path_or_alias(struct device_node *root,
+ const char *str)
+{
+ if (*str == '/')
+ return of_find_node_by_path_from(root, str);
+ else
+ return of_find_node_by_alias(root, str);
+
+}
+EXPORT_SYMBOL(of_find_node_by_path_or_alias);
+
+/**
* of_modalias_node - Lookup appropriate modalias for a device node
* @node: pointer to a device tree node
* @modalias: Pointer to buffer that modalias value will be copied into
@@ -1568,22 +1701,6 @@ int of_add_memory(struct device_node *node, bool dump)
return 0;
}
-static void __of_parse_phandles(struct device_node *node)
-{
- struct device_node *n;
- phandle phandle;
- int ret;
-
- ret = of_property_read_u32(node, "phandle", &phandle);
- if (!ret) {
- node->phandle = phandle;
- list_add_tail(&node->phandles, &phandle_list);
- }
-
- list_for_each_entry(n, &node->children, parent_list)
- __of_parse_phandles(n);
-}
-
struct device_node *of_chosen;
const char *of_model;
@@ -1602,7 +1719,7 @@ const struct of_device_id of_default_bus_match_table[] = {
int of_probe(void)
{
- struct device_node *memory;
+ struct device_node *memory, *node;
if(!root_node)
return -ENODEV;
@@ -1613,7 +1730,9 @@ int of_probe(void)
if (of_model)
barebox_set_model(of_model);
- __of_parse_phandles(root_node);
+ of_tree_for_each_node_from(node, root_node)
+ if (node->phandle)
+ list_add_tail(&node->phandles, &phandle_list);
memory = of_find_node_by_path("/memory");
if (memory)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 76d6bb1594..5055eee43c 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -185,9 +185,12 @@ struct device_node *of_unflatten_dtb(struct device_node *root, void *infdt)
if (merge && p) {
free(p->value);
p->value = xzalloc(len);
+ p->length = len;
memcpy(p->value, nodep, len);
} else {
- of_new_property(node, name, nodep, len);
+ p = of_new_property(node, name, nodep, len);
+ if (!strcmp(name, "phandle") && len == 4)
+ node->phandle = be32_to_cpup(p->value);
}
break;
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index a0f63d84f5..0bf9d08b83 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -32,6 +32,7 @@
#include <io.h>
#include <spi/spi.h>
#include <mach/io.h>
+#include <mach/iomux.h>
#include <mach/board.h>
#include <mach/cpu.h>
#include <linux/clk.h>
diff --git a/drivers/video/fb.c b/drivers/video/fb.c
index a4a8b00966..420e4e301c 100644
--- a/drivers/video/fb.c
+++ b/drivers/video/fb.c
@@ -1,4 +1,5 @@
#include <common.h>
+#include <malloc.h>
#include <fb.h>
#include <errno.h>
#include <command.h>
@@ -93,10 +94,31 @@ static struct file_operations fb_ops = {
.ioctl = fb_ioctl,
};
+static void fb_info(struct device_d *dev)
+{
+ struct fb_info *info = dev->priv;
+ int i;
+
+ if (!info->num_modes)
+ return;
+
+ printf("available modes:\n");
+
+ for (i = 0; i < info->num_modes; i++) {
+ struct fb_videomode *mode = &info->mode_list[i];
+
+ printf("%-10s %dx%d@%d\n", mode->name,
+ mode->xres, mode->yres, mode->refresh);
+ }
+
+ printf("\n");
+}
+
int register_framebuffer(struct fb_info *info)
{
int id = get_free_deviceid("fb");
struct device_d *dev;
+ int ret;
dev = &info->dev;
@@ -113,47 +135,13 @@ int register_framebuffer(struct fb_info *info)
dev->priv = info;
dev->id = id;
+ dev->info = fb_info;
sprintf(dev->name, "fb");
- info->dev.bus = &fb_bus;
- register_device(&info->dev);
-
- return 0;
-}
-
-static void fb_info(struct device_d *dev)
-{
- struct fb_info *info = dev->priv;
- int i;
-
- if (!info->num_modes)
- return;
-
- printf("available modes:\n");
-
- for (i = 0; i < info->num_modes; i++) {
- struct fb_videomode *mode = &info->mode_list[i];
-
- printf("%-10s %dx%d@%d\n", mode->name,
- mode->xres, mode->yres, mode->refresh);
- }
-
- printf("\n");
-}
-
-static struct driver_d fb_driver = {
- .name = "fb",
-};
-
-static int fb_match(struct device_d *dev, struct driver_d *drv)
-{
- return 0;
-}
-
-static int fb_probe(struct device_d *dev)
-{
- struct fb_info *info = dev->priv;
+ ret = register_device(&info->dev);
+ if (ret)
+ goto err_free;
dev_add_param_bool(dev, "enable", fb_enable_set, NULL,
&info->p_enable, info);
@@ -164,32 +152,16 @@ static int fb_probe(struct device_d *dev)
dev_set_param(dev, "mode_name", info->mode_list[0].name);
}
- dev->info = fb_info;
-
- return devfs_create(&info->cdev);
-}
-
-static void fb_remove(struct device_d *dev)
-{
-}
+ ret = devfs_create(&info->cdev);
+ if (ret)
+ goto err_unregister;
-struct bus_type fb_bus = {
- .name = "fb",
- .match = fb_match,
- .probe = fb_probe,
- .remove = fb_remove,
-};
+ return 0;
-static int fb_bus_init(void)
-{
- return bus_register(&fb_bus);
-}
-pure_initcall(fb_bus_init);
+err_unregister:
+ unregister_device(&info->dev);
+err_free:
+ free(dev->resource);
-static int fb_init_driver(void)
-{
- fb_driver.bus = &fb_bus;
- register_driver(&fb_driver);
- return 0;
+ return ret;
}
-device_initcall(fb_init_driver);