summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2015-04-13 12:57:13 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2015-04-13 12:57:13 +0200
commit9c4cf7d3b6b4ca24b3ebd6e003d3032a90af44b0 (patch)
tree67b5ff0cde85ca0b79bb3b070d78b5422b1f92f8 /arch
parentc41b60fe6a61942d43405709ca2c19742dd99552 (diff)
parentf929fab29c7817356c34be68671df00792fa9a30 (diff)
downloadbarebox-9c4cf7d3b6b4ca24b3ebd6e003d3032a90af44b0.tar.gz
barebox-9c4cf7d3b6b4ca24b3ebd6e003d3032a90af44b0.tar.xz
Merge branch 'for-next/pci'
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-imx/Kconfig1
-rw-r--r--arch/arm/mach-imx/Makefile2
-rw-r--r--arch/arm/mach-imx/clk-gate-exclusive.c103
-rw-r--r--arch/arm/mach-imx/clk-imx6.c29
-rw-r--r--arch/arm/mach-imx/clk.h3
5 files changed, 137 insertions, 1 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 517beb12df..4d257a87a6 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -174,6 +174,7 @@ config ARCH_IMX6
select CPU_V7
select PINCTRL_IMX_IOMUX_V3
select COMMON_CLK_OF_PROVIDER
+ select HW_HAS_PCI
config ARCH_IMX6SX
bool
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 048cac5fb0..ae953b1bf8 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -16,7 +16,7 @@ obj-$(CONFIG_IMX_IIM) += iim.o
obj-$(CONFIG_IMX_OCOTP) += ocotp.o
obj-$(CONFIG_NAND_IMX) += nand.o
lwl-$(CONFIG_ARCH_IMX_EXTERNAL_BOOT_NAND) += external-nand-boot.o
-obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-pfd.o clk-gate2.o
+obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-pfd.o clk-gate2.o clk-gate-exclusive.o
obj-y += devices.o imx.o esdctl.o
obj-y += boot.o
obj-$(CONFIG_BAREBOX_UPDATE) += imx-bbu-internal.o
diff --git a/arch/arm/mach-imx/clk-gate-exclusive.c b/arch/arm/mach-imx/clk-gate-exclusive.c
new file mode 100644
index 0000000000..db88db0237
--- /dev/null
+++ b/arch/arm/mach-imx/clk-gate-exclusive.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <io.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+
+#include "clk.h"
+
+/**
+ * struct clk_gate_exclusive - i.MX specific gate clock which is mutually
+ * exclusive with other gate clocks
+ *
+ * @gate: the parent class
+ * @exclusive_mask: mask of gate bits which are mutually exclusive to this
+ * gate clock
+ *
+ * The imx exclusive gate clock is a subclass of basic clk_gate
+ * with an addtional mask to indicate which other gate bits in the same
+ * register is mutually exclusive to this gate clock.
+ */
+struct clk_gate_exclusive {
+ struct clk clk;
+ void __iomem *reg;
+ int shift;
+ const char *parent;
+ u32 exclusive_mask;
+};
+
+static int clk_gate_exclusive_enable(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+ u32 val = readl(exgate->reg);
+
+ if (val & exgate->exclusive_mask)
+ return -EBUSY;
+
+ val |= 1 << exgate->shift;
+
+ writel(val, exgate->reg);
+
+ return 0;
+}
+
+static void clk_gate_exclusive_disable(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+ u32 val = readl(exgate->reg);
+
+ val &= ~(1 << exgate->shift);
+
+ writel(val, exgate->reg);
+}
+
+static int clk_gate_exclusive_is_enabled(struct clk *clk)
+{
+ struct clk_gate_exclusive *exgate = container_of(clk,
+ struct clk_gate_exclusive, clk);
+
+ return readl(exgate->reg) & (1 << exgate->shift);
+}
+
+static const struct clk_ops clk_gate_exclusive_ops = {
+ .enable = clk_gate_exclusive_enable,
+ .disable = clk_gate_exclusive_disable,
+ .is_enabled = clk_gate_exclusive_is_enabled,
+};
+
+struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u32 exclusive_mask)
+{
+ struct clk_gate_exclusive *exgate;
+ int ret;
+
+ exgate = xzalloc(sizeof(*exgate));
+ exgate->parent = parent;
+ exgate->clk.name = name;
+ exgate->clk.ops = &clk_gate_exclusive_ops;
+ exgate->clk.flags = CLK_SET_RATE_PARENT;
+ exgate->clk.parent_names = &exgate->parent;
+ exgate->clk.num_parents = 1;
+
+ exgate->reg = reg;
+ exgate->shift = shift;
+ exgate->exclusive_mask = exclusive_mask;
+
+ ret = clk_register(&exgate->clk);
+ if (ret) {
+ free(exgate);
+ return ERR_PTR(ret);
+ }
+
+ return &exgate->clk;
+}
diff --git a/arch/arm/mach-imx/clk-imx6.c b/arch/arm/mach-imx/clk-imx6.c
index 145b394d92..f51e559505 100644
--- a/arch/arm/mach-imx/clk-imx6.c
+++ b/arch/arm/mach-imx/clk-imx6.c
@@ -196,6 +196,26 @@ static const char *ipu2_di1_sels[] = {
"ldb_di1_podf",
};
+static const char *lvds_sels[] = {
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "dummy",
+ "pll4_audio",
+ "pll5_video",
+ "pll8_mlb",
+ "enet_ref",
+ "pcie_ref_125m",
+ "sata_ref_100m",
+};
+
+static const char *pcie_axi_sels[] = {
+ "axi",
+ "ahb",
+};
+
static struct clk_div_table clk_enet_ref_table[] = {
{ .val = 0, .div = 20, },
{ .val = 1, .div = 10, },
@@ -306,6 +326,12 @@ static int imx6_ccm_probe(struct device_d *dev)
clks[IMX6QDL_CLK_ENET_REF] = imx_clk_divider_table("enet_ref", "pll6_enet", base + 0xe0, 0, 2, clk_enet_ref_table);
+ clks[IMX6QDL_CLK_LVDS1_SEL] = imx_clk_mux("lvds1_sel", base + 0x160, 0, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+ clks[IMX6QDL_CLK_LVDS2_SEL] = imx_clk_mux("lvds2_sel", base + 0x160, 5, 5, lvds_sels, ARRAY_SIZE(lvds_sels));
+
+ clks[IMX6QDL_CLK_LVDS1_GATE] = imx_clk_gate_exclusive("lvds1_gate", "lvds1_sel", base + 0x160, 10, BIT(12));
+ clks[IMX6QDL_CLK_LVDS2_GATE] = imx_clk_gate_exclusive("lvds2_gate", "lvds2_sel", base + 0x160, 11, BIT(13));
+
/* name parent_name reg idx */
clks[IMX6QDL_CLK_PLL2_PFD0_352M] = imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0);
clks[IMX6QDL_CLK_PLL2_PFD1_594M] = imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1);
@@ -341,6 +367,7 @@ static int imx6_ccm_probe(struct device_d *dev)
clks[IMX6QDL_CLK_EIM_SLOW_SEL] = imx_clk_mux("eim_slow_sel", base + 0x1c, 29, 2, eim_sels, ARRAY_SIZE(eim_sels));
clks[IMX6QDL_CLK_VDO_AXI_SEL] = imx_clk_mux("vdo_axi_sel", base + 0x18, 11, 1, vdo_axi_sels, ARRAY_SIZE(vdo_axi_sels));
clks[IMX6QDL_CLK_CKO1_SEL] = imx_clk_mux("cko1_sel", base + 0x60, 0, 4, cko1_sels, ARRAY_SIZE(cko1_sels));
+ clks[IMX6QDL_CLK_PCIE_AXI_SEL] = imx_clk_mux("pcie_axi_sel", base + 0x18, 10, 1, pcie_axi_sels, ARRAY_SIZE(pcie_axi_sels));
/* name reg shift width busy: reg, shift parent_names num_parents */
clks[IMX6QDL_CLK_PERIPH] = imx_clk_busy_mux("periph", base + 0x14, 25, 1, base + 0x48, 5, periph_sels, ARRAY_SIZE(periph_sels));
@@ -435,6 +462,8 @@ static int imx6_ccm_probe(struct device_d *dev)
clk_enable(clks[IMX6QDL_CLK_SATA_REF_100M]);
clk_enable(clks[IMX6QDL_CLK_ENFC_PODF]);
+ clk_set_parent(clks[IMX6QDL_CLK_LVDS1_SEL], clks[IMX6QDL_CLK_SATA_REF_100M]);
+
return 0;
}
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 8ec3eb5430..c8da2fa70c 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -92,4 +92,7 @@ static inline struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg,
return imx_clk_mux(name, reg, shift, width, parents, num_parents);
}
+struct clk *imx_clk_gate_exclusive(const char *name, const char *parent,
+ void __iomem *reg, u8 shift, u32 exclusive_mask);
+
#endif /* __IMX_CLK_H */