summaryrefslogtreecommitdiff
path: root/arch/arm/mach-omap2/control.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-22 09:24:55 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-22 09:24:55 -0700
commit8b3c8ba3d8c2680dab5363a80c024965cac08b1e (patch)
tree18150efb36891e6e76e2cad89c1b2fcc5faeae93 /arch/arm/mach-omap2/control.c
parentd34dc4f9e88e4b6beefb819e4e743fd6160a9b75 (diff)
parent48c1078509b47b38802329028ccfd77783bcff99 (diff)
downloadlinux-rt-8b3c8ba3d8c2680dab5363a80c024965cac08b1e.tar.gz
Merge tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC late changes from Olof Johansson: "We were expecting to sit on this branch through most of the merge window since the contents was merged into our tree late, but we ended up sitting on all of our contents so it can go in with the rest. The contents here is: - a large branch of cleanups of the CM/PRM blocks on OMAP. - a couple of patches plumbing up CM/PRM on OMAP5 and DRA7. - a branch with DT updates for Freescale i.MX. including some shuffling from .dts to .dtsi (include) files that causes a little churn" * tag 'armsoc-late' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (78 commits) ARM: OMAP2+: Fix booting with configs that don't have MFD_SYSCON ARM: OMAP4+: control: add support for initializing control module via DT ARM: dts: dra7: add minimal l4 bus layout with control module support ARM: dts: omap5: add minimal l4 bus layout with control module support ARM: OMAP4+: control: remove support for legacy pad read/write ARM: OMAP4: display: convert display to use syscon for dsi muxing ARM: dts: omap4: add minimal l4 bus layout with control module support ARM: dts: am4372: add minimal l4 bus layout with control module support ARM: dts: am43xx-epos-evm: fix pinmux node layout ARM: dts: am33xx: add minimal l4 bus layout with control module support ARM: dts: omap3: add minimal l4 bus layout with control module support ARM: dts: omap24xx: add minimal l4 bus layout with control module support ARM: OMAP2+: control: add syscon support for register accesses ARM: OMAP2+: id: cache omap_type value ARM: OMAP2+: control: remove API for getting control module base address ARM: OMAP2+: clock: add low-level support for regmap ARM: OMAP4+: PRM: get rid of cpu_is_omap44xx calls from interrupt init ARM: OMAP4+: PRM: setup prm_features from the PRM init time flags ARM: OMAP2+: CM: move SoC specific init calls within a generic API ARM: OMAP4+: PRM: determine prm_device_inst based on DT compatibility ...
Diffstat (limited to 'arch/arm/mach-omap2/control.c')
-rw-r--r--arch/arm/mach-omap2/control.c201
1 files changed, 168 insertions, 33 deletions
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index da041b4ab29c..af95a624fe71 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -14,6 +14,9 @@
#include <linux/kernel.h>
#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
#include "soc.h"
#include "iomap.h"
@@ -25,13 +28,15 @@
#include "sdrc.h"
#include "pm.h"
#include "control.h"
+#include "clock.h"
/* Used by omap3_ctrl_save_padconf() */
#define START_PADCONF_SAVE 0x2
#define PADCONF_SAVE_DONE 0x1
static void __iomem *omap2_ctrl_base;
-static void __iomem *omap4_ctrl_pad_base;
+static s16 omap2_ctrl_offset;
+static struct regmap *omap2_ctrl_syscon;
#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
struct omap3_scratchpad {
@@ -133,66 +138,79 @@ struct omap3_control_regs {
static struct omap3_control_regs control_context;
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
-#define OMAP_CTRL_REGADDR(reg) (omap2_ctrl_base + (reg))
-#define OMAP4_CTRL_PAD_REGADDR(reg) (omap4_ctrl_pad_base + (reg))
-
-void __init omap2_set_globals_control(void __iomem *ctrl,
- void __iomem *ctrl_pad)
+void __init omap2_set_globals_control(void __iomem *ctrl)
{
omap2_ctrl_base = ctrl;
- omap4_ctrl_pad_base = ctrl_pad;
-}
-
-void __iomem *omap_ctrl_base_get(void)
-{
- return omap2_ctrl_base;
}
u8 omap_ctrl_readb(u16 offset)
{
- return readb_relaxed(OMAP_CTRL_REGADDR(offset));
+ u32 val;
+ u8 byte_offset = offset & 0x3;
+
+ val = omap_ctrl_readl(offset);
+
+ return (val >> (byte_offset * 8)) & 0xff;
}
u16 omap_ctrl_readw(u16 offset)
{
- return readw_relaxed(OMAP_CTRL_REGADDR(offset));
+ u32 val;
+ u16 byte_offset = offset & 0x2;
+
+ val = omap_ctrl_readl(offset);
+
+ return (val >> (byte_offset * 8)) & 0xffff;
}
u32 omap_ctrl_readl(u16 offset)
{
- return readl_relaxed(OMAP_CTRL_REGADDR(offset));
+ u32 val;
+
+ offset &= 0xfffc;
+ if (!omap2_ctrl_syscon)
+ val = readl_relaxed(omap2_ctrl_base + offset);
+ else
+ regmap_read(omap2_ctrl_syscon, omap2_ctrl_offset + offset,
+ &val);
+
+ return val;
}
void omap_ctrl_writeb(u8 val, u16 offset)
{
- writeb_relaxed(val, OMAP_CTRL_REGADDR(offset));
+ u32 tmp;
+ u8 byte_offset = offset & 0x3;
+
+ tmp = omap_ctrl_readl(offset);
+
+ tmp &= 0xffffffff ^ (0xff << (byte_offset * 8));
+ tmp |= val << (byte_offset * 8);
+
+ omap_ctrl_writel(tmp, offset);
}
void omap_ctrl_writew(u16 val, u16 offset)
{
- writew_relaxed(val, OMAP_CTRL_REGADDR(offset));
-}
+ u32 tmp;
+ u8 byte_offset = offset & 0x2;
-void omap_ctrl_writel(u32 val, u16 offset)
-{
- writel_relaxed(val, OMAP_CTRL_REGADDR(offset));
-}
+ tmp = omap_ctrl_readl(offset);
-/*
- * On OMAP4 control pad are not addressable from control
- * core base. So the common omap_ctrl_read/write APIs breaks
- * Hence export separate APIs to manage the omap4 pad control
- * registers. This APIs will work only for OMAP4
- */
+ tmp &= 0xffffffff ^ (0xffff << (byte_offset * 8));
+ tmp |= val << (byte_offset * 8);
-u32 omap4_ctrl_pad_readl(u16 offset)
-{
- return readl_relaxed(OMAP4_CTRL_PAD_REGADDR(offset));
+ omap_ctrl_writel(tmp, offset);
}
-void omap4_ctrl_pad_writel(u32 val, u16 offset)
+void omap_ctrl_writel(u32 val, u16 offset)
{
- writel_relaxed(val, OMAP4_CTRL_PAD_REGADDR(offset));
+ offset &= 0xfffc;
+ if (!omap2_ctrl_syscon)
+ writel_relaxed(val, omap2_ctrl_base + offset);
+ else
+ regmap_write(omap2_ctrl_syscon, omap2_ctrl_offset + offset,
+ val);
}
#ifdef CONFIG_ARCH_OMAP3
@@ -611,3 +629,120 @@ void __init omap3_ctrl_init(void)
omap3_ctrl_setup_d2d_padconf();
}
#endif /* CONFIG_ARCH_OMAP3 && CONFIG_PM */
+
+struct control_init_data {
+ int index;
+ s16 offset;
+};
+
+static struct control_init_data ctrl_data = {
+ .index = TI_CLKM_CTRL,
+};
+
+static const struct control_init_data omap2_ctrl_data = {
+ .index = TI_CLKM_CTRL,
+ .offset = -OMAP2_CONTROL_GENERAL,
+};
+
+static const struct of_device_id omap_scrm_dt_match_table[] = {
+ { .compatible = "ti,am3-scm", .data = &ctrl_data },
+ { .compatible = "ti,am4-scm", .data = &ctrl_data },
+ { .compatible = "ti,omap2-scm", .data = &omap2_ctrl_data },
+ { .compatible = "ti,omap3-scm", .data = &omap2_ctrl_data },
+ { .compatible = "ti,dm816-scrm", .data = &ctrl_data },
+ { .compatible = "ti,omap4-scm-core", .data = &ctrl_data },
+ { .compatible = "ti,omap5-scm-core", .data = &ctrl_data },
+ { .compatible = "ti,dra7-scm-core", .data = &ctrl_data },
+ { }
+};
+
+/**
+ * omap2_control_base_init - initialize iomappings for the control driver
+ *
+ * Detects and initializes the iomappings for the control driver, based
+ * on the DT data. Returns 0 in success, negative error value
+ * otherwise.
+ */
+int __init omap2_control_base_init(void)
+{
+ struct device_node *np;
+ const struct of_device_id *match;
+ struct control_init_data *data;
+
+ for_each_matching_node_and_match(np, omap_scrm_dt_match_table, &match) {
+ data = (struct control_init_data *)match->data;
+
+ omap2_ctrl_base = of_iomap(np, 0);
+ if (!omap2_ctrl_base)
+ return -ENOMEM;
+
+ omap2_ctrl_offset = data->offset;
+ }
+
+ return 0;
+}
+
+/**
+ * omap_control_init - low level init for the control driver
+ *
+ * Initializes the low level clock infrastructure for control driver.
+ * Returns 0 in success, negative error value in failure.
+ */
+int __init omap_control_init(void)
+{
+ struct device_node *np, *scm_conf;
+ const struct of_device_id *match;
+ const struct omap_prcm_init_data *data;
+ int ret;
+ struct regmap *syscon;
+
+ for_each_matching_node_and_match(np, omap_scrm_dt_match_table, &match) {
+ data = match->data;
+
+ /*
+ * Check if we have scm_conf node, if yes, use this to
+ * access clock registers.
+ */
+ scm_conf = of_get_child_by_name(np, "scm_conf");
+
+ if (scm_conf) {
+ syscon = syscon_node_to_regmap(scm_conf);
+
+ if (IS_ERR(syscon))
+ return PTR_ERR(syscon);
+
+ omap2_ctrl_syscon = syscon;
+
+ if (of_get_child_by_name(scm_conf, "clocks")) {
+ ret = omap2_clk_provider_init(scm_conf,
+ data->index,
+ syscon, NULL);
+ if (ret)
+ return ret;
+ }
+
+ iounmap(omap2_ctrl_base);
+ omap2_ctrl_base = NULL;
+ } else {
+ /* No scm_conf found, direct access */
+ ret = omap2_clk_provider_init(np, data->index, NULL,
+ omap2_ctrl_base);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * omap3_control_legacy_iomap_init - legacy iomap init for clock providers
+ *
+ * Legacy iomap init for clock provider. Needed only by legacy boot mode,
+ * where the base addresses are not parsed from DT, but still required
+ * by the clock driver to be setup properly.
+ */
+void __init omap3_control_legacy_iomap_init(void)
+{
+ omap2_clk_legacy_provider_init(TI_CLKM_SCRM, omap2_ctrl_base);
+}