Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 566a9b05 authored by Tony Lindgren's avatar Tony Lindgren
Browse files

bus: ti-sysc: Handle module quirks based dts configuration



Let's configure few module quirks via device tree using the
properties for "ti,no-idle-on-init", "ti,no-reset-on-init"
and "ti,sysc-delay-us".

Let's also reorder the probe a bit so we have pdata available
earlier, and move the PM runtime calls to sysc_init_module()
from sysc_read_revision().

Signed-off-by: default avatarTony Lindgren <tony@atomide.com>
parent a7199e2b
Loading
Loading
Loading
Loading
+96 −18
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@ static const char * const clock_names[] = { "fck", "ick", };
 * @legacy_mode: configured for legacy mode if set
 * @cap: interconnect target module capabilities
 * @cfg: interconnect target module configuration
 * @name: name if available
 * @revision: interconnect target module revision
 */
struct sysc {
	struct device *dev;
@@ -61,12 +63,32 @@ struct sysc {
	const char *legacy_mode;
	const struct sysc_capabilities *cap;
	struct sysc_config cfg;
	const char *name;
	u32 revision;
};

static u32 sysc_read(struct sysc *ddata, int offset)
{
	if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) {
		u32 val;

		val = readw_relaxed(ddata->module_va + offset);
		val |= (readw_relaxed(ddata->module_va + offset + 4) << 16);

		return val;
	}

	return readl_relaxed(ddata->module_va + offset);
}

static u32 sysc_read_revision(struct sysc *ddata)
{
	return readl_relaxed(ddata->module_va +
			     ddata->offsets[SYSC_REVISION]);
	int offset = ddata->offsets[SYSC_REVISION];

	if (offset < 0)
		return 0;

	return sysc_read(ddata, offset);
}

static int sysc_get_one_clock(struct sysc *ddata,
@@ -393,22 +415,12 @@ static int sysc_map_and_check_registers(struct sysc *ddata)
 */
static int sysc_show_rev(char *bufp, struct sysc *ddata)
{
	int error, len;
	int len;

	if (ddata->offsets[SYSC_REVISION] < 0)
		return sprintf(bufp, ":NA");

	error = pm_runtime_get_sync(ddata->dev);
	if (error < 0) {
		pm_runtime_put_noidle(ddata->dev);

		return 0;
	}

	len = sprintf(bufp, ":%08x", sysc_read_revision(ddata));

	pm_runtime_mark_last_busy(ddata->dev);
	pm_runtime_put_autosuspend(ddata->dev);
	len = sprintf(bufp, ":%08x", ddata->revision);

	return len;
}
@@ -488,6 +500,66 @@ static const struct dev_pm_ops sysc_pm_ops = {
			   NULL)
};

/* At this point the module is configured enough to read the revision */
static int sysc_init_module(struct sysc *ddata)
{
	int error;

	error = pm_runtime_get_sync(ddata->dev);
	if (error < 0) {
		pm_runtime_put_noidle(ddata->dev);

		return 0;
	}
	ddata->revision = sysc_read_revision(ddata);
	pm_runtime_put_sync(ddata->dev);

	return 0;
}

/* Device tree configured quirks */
struct sysc_dts_quirk {
	const char *name;
	u32 mask;
};

static const struct sysc_dts_quirk sysc_dts_quirks[] = {
	{ .name = "ti,no-idle-on-init",
	  .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, },
	{ .name = "ti,no-reset-on-init",
	  .mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
};

static int sysc_init_dts_quirks(struct sysc *ddata)
{
	struct device_node *np = ddata->dev->of_node;
	const struct property *prop;
	int i, len, error;
	u32 val;

	ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);

	for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
		prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
		if (!prop)
			break;

		ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
	}

	error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
	if (!error) {
		if (val > 255) {
			dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n",
				 val);
		}

		ddata->cfg.srst_udelay = (u8)val;
	}

	return 0;
}

static void sysc_unprepare(struct sysc *ddata)
{
	int i;
@@ -722,7 +794,6 @@ static int sysc_init_match(struct sysc *ddata)

static int sysc_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
	struct sysc *ddata;
	int error;

@@ -731,12 +802,16 @@ static int sysc_probe(struct platform_device *pdev)
		return -ENOMEM;

	ddata->dev = &pdev->dev;
	ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
	platform_set_drvdata(pdev, ddata);

	error = sysc_init_match(ddata);
	if (error)
		return error;

	error = sysc_init_dts_quirks(ddata);
	if (error)
		goto unprepare;

	error = sysc_get_clocks(ddata);
	if (error)
		return error;
@@ -745,9 +820,12 @@ static int sysc_probe(struct platform_device *pdev)
	if (error)
		goto unprepare;

	platform_set_drvdata(pdev, ddata);

	pm_runtime_enable(ddata->dev);

	error = sysc_init_module(ddata);
	if (error)
		goto unprepare;

	error = pm_runtime_get_sync(ddata->dev);
	if (error < 0) {
		pm_runtime_put_noidle(ddata->dev);
+6 −0
Original line number Diff line number Diff line
@@ -41,6 +41,10 @@ struct sysc_regbits {
	s8 emufree_shift;
};

#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)
#define SYSC_QUIRK_OPT_CLKS_IN_RESET	BIT(3)
#define SYSC_QUIRK_16BIT		BIT(2)
#define SYSC_QUIRK_UNCACHED		BIT(1)
#define SYSC_QUIRK_USE_CLOCKACT		BIT(0)
@@ -61,9 +65,11 @@ struct sysc_capabilities {

/**
 * struct sysc_config - configuration for an interconnect target module
 * @srst_udelay: optional delay needed after OCP soft reset
 * @quirks: bitmask of enabled quirks
 */
struct sysc_config {
	u8 srst_udelay;
	u32 quirks;
};