diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/mvebu/Makefile | 5 | ||||
-rw-r--r-- | drivers/clk/mvebu/armada-370.c | 160 | ||||
-rw-r--r-- | drivers/clk/mvebu/armada-xp.c | 194 | ||||
-rw-r--r-- | drivers/clk/mvebu/common.c | 208 | ||||
-rw-r--r-- | drivers/clk/mvebu/common.h | 70 | ||||
-rw-r--r-- | drivers/clk/mvebu/dove.c | 179 | ||||
-rw-r--r-- | drivers/clk/mvebu/kirkwood.c | 224 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 4 | ||||
-rw-r--r-- | drivers/mci/sdhci.h | 4 | ||||
-rw-r--r-- | drivers/mfd/syscon.c | 2 | ||||
-rw-r--r-- | drivers/mtd/ubi/cdev.c | 6 | ||||
-rw-r--r-- | drivers/mtd/ubi/kapi.c | 93 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi-barebox.h | 8 | ||||
-rw-r--r-- | drivers/mtd/ubi/ubi.h | 2 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 63 | ||||
-rw-r--r-- | drivers/of/base.c | 155 | ||||
-rw-r--r-- | drivers/of/fdt.c | 5 | ||||
-rw-r--r-- | drivers/spi/atmel_spi.c | 1 | ||||
-rw-r--r-- | drivers/video/fb.c | 98 |
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); |