summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2017-12-15 20:41:23 +0300
committerTony Lindgren <tony@atomide.com>2017-12-21 18:28:54 +0300
commitc5a2de97fbd2979fab291fb048084d3fddd322dd (patch)
tree45dfca45e1e9c683c961cb20936d464a2380f673
parent566a9b05e1fa47dcfb93a4459145d0fdc06d3046 (diff)
downloadlinux-c5a2de97fbd2979fab291fb048084d3fddd322dd.tar.xz
bus: ti-sysc: Add parsing of module capabilities
We need to configure the interconnect target module based on the device three configuration. Let's also add a new quirk for SYSC_QUIRK_RESET_STATUS to indicate that the SYSCONFIG reset bit changes after the reset is done. Signed-off-by: Tony Lindgren <tony@atomide.com>
-rw-r--r--drivers/bus/ti-sysc.c100
-rw-r--r--include/linux/platform_data/ti-sysc.h10
2 files changed, 110 insertions, 0 deletions
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index 090612460cef..2c62985a345f 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -39,6 +39,9 @@ enum sysc_clocks {
static const char * const clock_names[] = { "fck", "ick", };
+#define SYSC_IDLEMODE_MASK 3
+#define SYSC_CLOCKACTIVITY_MASK 3
+
/**
* struct sysc - TI sysc interconnect target module registers and capabilities
* @dev: struct device pointer
@@ -517,6 +520,91 @@ static int sysc_init_module(struct sysc *ddata)
return 0;
}
+static int sysc_init_sysc_mask(struct sysc *ddata)
+{
+ struct device_node *np = ddata->dev->of_node;
+ int error;
+ u32 val;
+
+ error = of_property_read_u32(np, "ti,sysc-mask", &val);
+ if (error)
+ return 0;
+
+ if (val)
+ ddata->cfg.sysc_val = val & ddata->cap->sysc_mask;
+ else
+ ddata->cfg.sysc_val = ddata->cap->sysc_mask;
+
+ return 0;
+}
+
+static int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes,
+ const char *name)
+{
+ struct device_node *np = ddata->dev->of_node;
+ struct property *prop;
+ const __be32 *p;
+ u32 val;
+
+ of_property_for_each_u32(np, name, prop, p, val) {
+ if (val >= SYSC_NR_IDLEMODES) {
+ dev_err(ddata->dev, "invalid idlemode: %i\n", val);
+ return -EINVAL;
+ }
+ *idlemodes |= (1 << val);
+ }
+
+ return 0;
+}
+
+static int sysc_init_idlemodes(struct sysc *ddata)
+{
+ int error;
+
+ error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes,
+ "ti,sysc-midle");
+ if (error)
+ return error;
+
+ error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes,
+ "ti,sysc-sidle");
+ if (error)
+ return error;
+
+ return 0;
+}
+
+/*
+ * Only some devices on omap4 and later have SYSCONFIG reset done
+ * bit. We can detect this if there is no SYSSTATUS at all, or the
+ * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers
+ * have multiple bits for the child devices like OHCI and EHCI.
+ * Depends on SYSC being parsed first.
+ */
+static int sysc_init_syss_mask(struct sysc *ddata)
+{
+ struct device_node *np = ddata->dev->of_node;
+ int error;
+ u32 val;
+
+ error = of_property_read_u32(np, "ti,syss-mask", &val);
+ if (error) {
+ if ((ddata->cap->type == TI_SYSC_OMAP4 ||
+ ddata->cap->type == TI_SYSC_OMAP4_TIMER) &&
+ (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
+ ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
+
+ return 0;
+ }
+
+ if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET))
+ ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS;
+
+ ddata->cfg.syss_mask = val;
+
+ return 0;
+}
+
/* Device tree configured quirks */
struct sysc_dts_quirk {
const char *name;
@@ -820,6 +908,18 @@ static int sysc_probe(struct platform_device *pdev)
if (error)
goto unprepare;
+ error = sysc_init_sysc_mask(ddata);
+ if (error)
+ goto unprepare;
+
+ error = sysc_init_idlemodes(ddata);
+ if (error)
+ goto unprepare;
+
+ error = sysc_init_syss_mask(ddata);
+ if (error)
+ goto unprepare;
+
pm_runtime_enable(ddata->dev);
error = sysc_init_module(ddata);
diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
index 28e5a61d4abc..1be356330b96 100644
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -41,6 +41,7 @@ struct sysc_regbits {
s8 emufree_shift;
};
+#define SYSC_QUIRK_RESET_STATUS BIT(7)
#define SYSC_QUIRK_NO_IDLE_ON_INIT BIT(6)
#define SYSC_QUIRK_NO_RESET_ON_INIT BIT(5)
#define SYSC_QUIRK_OPT_CLKS_NEEDED BIT(4)
@@ -49,6 +50,8 @@ struct sysc_regbits {
#define SYSC_QUIRK_UNCACHED BIT(1)
#define SYSC_QUIRK_USE_CLOCKACT BIT(0)
+#define SYSC_NR_IDLEMODES 4
+
/**
* struct sysc_capabilities - capabilities for an interconnect target module
*
@@ -65,10 +68,17 @@ struct sysc_capabilities {
/**
* struct sysc_config - configuration for an interconnect target module
+ * @sysc_val: configured value for sysc register
+ * @midlemodes: bitmask of supported master idle modes
+ * @sidlemodes: bitmask of supported master idle modes
* @srst_udelay: optional delay needed after OCP soft reset
* @quirks: bitmask of enabled quirks
*/
struct sysc_config {
+ u32 sysc_val;
+ u32 syss_mask;
+ u8 midlemodes;
+ u8 sidlemodes;
u8 srst_udelay;
u32 quirks;
};