diff options
Diffstat (limited to 'arch/arm/mach-omap2/control.c')
-rw-r--r-- | arch/arm/mach-omap2/control.c | 201 |
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); +} |