2020-02-21 19:53:26

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 0/7] ti-sysc driver fix for hdq1w and few improvments

Hi all,

Here are some ti-sysc interconnect target module driver fixes and
improvments.

There's a fix for 1-wire reset, the rest can wait for v5.7 merge
window.

Regards,

Tony



Tony Lindgren (7):
bus: ti-sysc: Fix 1-wire reset quirk
bus: ti-sysc: Rename clk related quirks to pre_reset and post_reset
quirks
ti-sysc: Improve reset to work with modules with no sysconfig
bus: ti-sysc: Consider non-existing registers too when matching quirks
bus: ti-sysc: Don't warn about legacy property for nested ti-sysc
devices
bus: ti-sysc: Implement SoC revision handling
bus: ti-sysc: Handle module unlock quirk needed for some RTC

arch/arm/mach-omap2/pdata-quirks.c | 6 +
drivers/bus/ti-sysc.c | 430 ++++++++++++++++++++------
include/linux/platform_data/ti-sysc.h | 2 +
3 files changed, 348 insertions(+), 90 deletions(-)

--
2.25.1


2020-02-21 19:53:26

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 1/7] bus: ti-sysc: Fix 1-wire reset quirk

Because of the i2c quirk we have the reset quirks named in a confusing
way. Let's fix the 1-wire quirk accordinlyg. Then let's switch to using
better naming later on.

Fixes: 4e23be473e30 ("bus: ti-sysc: Add support for module specific reset quirks")
Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -1400,7 +1400,7 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
}

/* 1-wire needs module's internal clocks enabled for reset */
-static void sysc_clk_enable_quirk_hdq1w(struct sysc *ddata)
+static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata)
{
int offset = 0x0c; /* HDQ_CTRL_STATUS */
u16 val;
@@ -1488,7 +1488,7 @@ static void sysc_init_module_quirks(struct sysc *ddata)
return;

if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
- ddata->clk_enable_quirk = sysc_clk_enable_quirk_hdq1w;
+ ddata->clk_disable_quirk = sysc_pre_reset_quirk_hdq1w;

return;
}
--
2.25.1

2020-02-21 19:53:40

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 2/7] bus: ti-sysc: Rename clk related quirks to pre_reset and post_reset quirks

The clk_disable_quirk and clk_enable_quirk should really be called
pre_reset_quirk and post_reset_quirk to avoid confusion like we had
with hdq1w reset.

Let's also rename the related functions so the code is easier to follow.
Note that we also have reset_done_quirk that is needed in some cases
after checking the separate register for reset done bit.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 32 ++++++++++++++++----------------
1 file changed, 16 insertions(+), 16 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -70,8 +70,8 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
* @child_needs_resume: runtime resume needed for child on resume from suspend
* @disable_on_idle: status flag used for disabling modules with resets
* @idle_work: work structure used to perform delayed idle on a module
- * @clk_enable_quirk: module specific clock enable quirk
- * @clk_disable_quirk: module specific clock disable quirk
+ * @pre_reset_quirk: module specific pre-reset quirk
+ * @post_reset_quirk: module specific post-reset quirk
* @reset_done_quirk: module specific reset done quirk
* @module_enable_quirk: module specific enable quirk
* @module_disable_quirk: module specific disable quirk
@@ -97,8 +97,8 @@ struct sysc {
unsigned int needs_resume:1;
unsigned int child_needs_resume:1;
struct delayed_work idle_work;
- void (*clk_enable_quirk)(struct sysc *sysc);
- void (*clk_disable_quirk)(struct sysc *sysc);
+ void (*pre_reset_quirk)(struct sysc *sysc);
+ void (*post_reset_quirk)(struct sysc *sysc);
void (*reset_done_quirk)(struct sysc *sysc);
void (*module_enable_quirk)(struct sysc *sysc);
void (*module_disable_quirk)(struct sysc *sysc);
@@ -1418,7 +1418,7 @@ static void sysc_module_enable_quirk_aess(struct sysc *ddata)
sysc_write(ddata, offset, 1);
}

-/* I2C needs extra enable bit toggling for reset */
+/* I2C needs to be disabled for reset */
static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable)
{
int offset;
@@ -1439,14 +1439,14 @@ static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable)
sysc_write(ddata, offset, val);
}

-static void sysc_clk_enable_quirk_i2c(struct sysc *ddata)
+static void sysc_pre_reset_quirk_i2c(struct sysc *ddata)
{
- sysc_clk_quirk_i2c(ddata, true);
+ sysc_clk_quirk_i2c(ddata, false);
}

-static void sysc_clk_disable_quirk_i2c(struct sysc *ddata)
+static void sysc_post_reset_quirk_i2c(struct sysc *ddata)
{
- sysc_clk_quirk_i2c(ddata, false);
+ sysc_clk_quirk_i2c(ddata, true);
}

/* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */
@@ -1488,14 +1488,14 @@ static void sysc_init_module_quirks(struct sysc *ddata)
return;

if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) {
- ddata->clk_disable_quirk = sysc_pre_reset_quirk_hdq1w;
+ ddata->pre_reset_quirk = sysc_pre_reset_quirk_hdq1w;

return;
}

if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) {
- ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c;
- ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c;
+ ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c;
+ ddata->post_reset_quirk = sysc_post_reset_quirk_i2c;

return;
}
@@ -1583,8 +1583,8 @@ static int sysc_reset(struct sysc *ddata)
else
syss_done = ddata->cfg.syss_mask;

- if (ddata->clk_disable_quirk)
- ddata->clk_disable_quirk(ddata);
+ if (ddata->pre_reset_quirk)
+ ddata->pre_reset_quirk(ddata);

sysc_val = sysc_read_sysconfig(ddata);
sysc_val |= sysc_mask;
@@ -1594,8 +1594,8 @@ static int sysc_reset(struct sysc *ddata)
usleep_range(ddata->cfg.srst_udelay,
ddata->cfg.srst_udelay * 2);

- if (ddata->clk_enable_quirk)
- ddata->clk_enable_quirk(ddata);
+ if (ddata->post_reset_quirk)
+ ddata->post_reset_quirk(ddata);

/* Poll on reset status */
if (syss_offset >= 0) {
--
2.25.1

2020-02-21 19:53:48

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 4/7] bus: ti-sysc: Consider non-existing registers too when matching quirks

We are currently setting -1 for non-existing sysconfig related registers
for quirks, but setting -ENODEV elsewhere. And for matching the quirks,
we're now just ignoring the non-existing registers. This will cause issues
with misdetecting DSS registers as the hardware revision numbers can have
duplicates.

To avoid this, let's standardize on using -ENODEV also for the quirks
instead of -1. That way we can always just test for a match without adding
any more complicated logic.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 120 ++++++++++++++++++++----------------------
1 file changed, 57 insertions(+), 63 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -1216,16 +1216,16 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
- SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff,
+ SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
- SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff,
+ SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff,
SYSC_QUIRK_LEGACY_IDLE),
SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
0),
/* Some timers on omap4 and later */
- SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff,
+ SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff,
0),
- SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
+ SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff,
0),
SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE),
@@ -1238,18 +1238,18 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE),

/* Quirks that need to be set based on the module address */
- SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -1, 0x50000800, 0xffffffff,
+ SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff,
SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT |
SYSC_QUIRK_SWSUP_SIDLE),

/* Quirks that need to be set based on detected module */
- SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff,
+ SYSC_QUIRK("aess", 0, 0, 0x10, -ENODEV, 0x40000000, 0xffffffff,
SYSC_MODULE_QUIRK_AESS),
- SYSC_QUIRK("dcan", 0x48480000, 0x20, -1, -1, 0xa3170504, 0xffffffff,
+ SYSC_QUIRK("dcan", 0x48480000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff,
SYSC_QUIRK_CLKDM_NOAUTO),
- SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -1, 0x500a0200, 0xffffffff,
+ SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
SYSC_QUIRK_CLKDM_NOAUTO),
- SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -1, 0x500a0200, 0xffffffff,
+ SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff,
SYSC_QUIRK_CLKDM_NOAUTO),
SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff,
SYSC_MODULE_QUIRK_HDQ1W),
@@ -1263,12 +1263,12 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_MODULE_QUIRK_I2C),
SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0,
SYSC_MODULE_QUIRK_I2C),
- SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0),
- SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff,
+ SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0),
+ SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff,
SYSC_MODULE_QUIRK_SGX),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
- SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -1, 0x4ea2080d, 0xffffffff,
+ SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0,
SYSC_MODULE_QUIRK_WDT),
@@ -1277,57 +1277,57 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE),

#ifdef DEBUG
- SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
- SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
- SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0),
- SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("adc", 0, 0, 0x10, -ENODEV, 0x47300001, 0xffffffff, 0),
+ SYSC_QUIRK("atl", 0, 0, -ENODEV, -ENODEV, 0x0a070100, 0xffffffff, 0),
+ SYSC_QUIRK("cm", 0, 0, -ENODEV, -ENODEV, 0x40000301, 0xffffffff, 0),
+ SYSC_QUIRK("control", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0),
SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
0xffff00f0, 0),
- SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0xa3170504, 0xffffffff, 0),
- SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0x4edb1902, 0xffffffff, 0),
- SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0),
- SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
+ SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 0),
+ SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0x4edb1902, 0xffffffff, 0),
+ SYSC_QUIRK("dmic", 0, 0, 0x10, -ENODEV, 0x50010000, 0xffffffff, 0),
+ SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0),
SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0),
- SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
- SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
- SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, 0),
+ SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0),
+ SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0),
+ SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0),
SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
- SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
- SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
- SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
- SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
- SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
- SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0),
+ SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0),
+ SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff, 0),
+ SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0),
+ SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0),
+ SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0),
+ SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0),
SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0),
- SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
- SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0),
+ SYSC_QUIRK("mailbox", 0, 0, 0x10, -ENODEV, 0x00000400, 0xffffffff, 0),
+ SYSC_QUIRK("m3", 0, 0, -ENODEV, -ENODEV, 0x5f580105, 0x0fff0f00, 0),
SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
- SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
- SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
- SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0),
- SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
- SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
- SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
- SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
- SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0),
- SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0),
- SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0),
- SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
- SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0),
+ SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0),
+ SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0),
+ SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0),
+ SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0),
+ SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x40000900, 0xffffffff, 0),
+ SYSC_QUIRK("scrm", 0, 0, -ENODEV, -ENODEV, 0x00000010, 0xffffffff, 0),
+ SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0),
SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
- SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
- SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
- SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
- SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0),
- SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
- SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
+ SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0),
+ SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
+ SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0),
+ SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0),
+ SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0, 0),
+ SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
- SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
- SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
+ SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff, 0),
+ SYSC_QUIRK("vfpe", 0, 0, 0x104, -ENODEV, 0x4d001200, 0xffffffff, 0),
#endif
};

@@ -1349,16 +1349,13 @@ static void sysc_init_early_quirks(struct sysc *ddata)
if (q->base != ddata->module_pa)
continue;

- if (q->rev_offset >= 0 &&
- q->rev_offset != ddata->offsets[SYSC_REVISION])
+ if (q->rev_offset != ddata->offsets[SYSC_REVISION])
continue;

- if (q->sysc_offset >= 0 &&
- q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+ if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
continue;

- if (q->syss_offset >= 0 &&
- q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+ if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
continue;

ddata->name = q->name;
@@ -1378,16 +1375,13 @@ static void sysc_init_revision_quirks(struct sysc *ddata)
if (q->base && q->base != ddata->module_pa)
continue;

- if (q->rev_offset >= 0 &&
- q->rev_offset != ddata->offsets[SYSC_REVISION])
+ if (q->rev_offset != ddata->offsets[SYSC_REVISION])
continue;

- if (q->sysc_offset >= 0 &&
- q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
+ if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG])
continue;

- if (q->syss_offset >= 0 &&
- q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
+ if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS])
continue;

if (q->revision == ddata->revision ||
--
2.25.1

2020-02-21 19:54:20

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 7/7] bus: ti-sysc: Handle module unlock quirk needed for some RTC

The RTC modules on am3 and am4 need quirk handling to unlock and lock
them for reset so let's add the quirk handling based on what we already
have for legacy platform data. In later patches we will simply drop the
RTC related platform data and the old quirk handling.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 74 ++++++++++++++++++++++++---
include/linux/platform_data/ti-sysc.h | 1 +
2 files changed, 69 insertions(+), 6 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -110,6 +110,8 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
* @reset_done_quirk: module specific reset done quirk
* @module_enable_quirk: module specific enable quirk
* @module_disable_quirk: module specific disable quirk
+ * @module_unlock_quirk: module specific sysconfig unlock quirk
+ * @module_lock_quirk: module specific sysconfig lock quirk
*/
struct sysc {
struct device *dev;
@@ -137,6 +139,8 @@ struct sysc {
void (*reset_done_quirk)(struct sysc *sysc);
void (*module_enable_quirk)(struct sysc *sysc);
void (*module_disable_quirk)(struct sysc *sysc);
+ void (*module_unlock_quirk)(struct sysc *sysc);
+ void (*module_lock_quirk)(struct sysc *sysc);
};

static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
@@ -896,6 +900,22 @@ static void sysc_show_registers(struct sysc *ddata)
buf);
}

+/**
+ * sysc_write_sysconfig - handle sysconfig quirks for register write
+ * @ddata: device driver data
+ * @value: register value
+ */
+static void sysc_write_sysconfig(struct sysc *ddata, u32 value)
+{
+ if (ddata->module_unlock_quirk)
+ ddata->module_unlock_quirk(ddata);
+
+ sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], value);
+
+ if (ddata->module_lock_quirk)
+ ddata->module_lock_quirk(ddata);
+}
+
#define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
#define SYSC_CLOCACT_ICK 2

@@ -942,7 +962,7 @@ static int sysc_enable_module(struct device *dev)

reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
reg |= best_mode << regbits->sidle_shift;
- sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+ sysc_write_sysconfig(ddata, reg);

set_midle:
/* Set MIDLE mode */
@@ -961,14 +981,14 @@ static int sysc_enable_module(struct device *dev)

reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
reg |= best_mode << regbits->midle_shift;
- sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+ sysc_write_sysconfig(ddata, reg);

set_autoidle:
/* Autoidle bit must enabled separately if available */
if (regbits->autoidle_shift >= 0 &&
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
reg |= 1 << regbits->autoidle_shift;
- sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+ sysc_write_sysconfig(ddata, reg);
}

if (ddata->module_enable_quirk)
@@ -1026,7 +1046,7 @@ static int sysc_disable_module(struct device *dev)

reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
reg |= best_mode << regbits->midle_shift;
- sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+ sysc_write_sysconfig(ddata, reg);

set_sidle:
/* Set SIDLE mode */
@@ -1049,7 +1069,7 @@ static int sysc_disable_module(struct device *dev)
if (regbits->autoidle_shift >= 0 &&
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift))
reg |= 1 << regbits->autoidle_shift;
- sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg);
+ sysc_write_sysconfig(ddata, reg);

return 0;
}
@@ -1301,6 +1321,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0),
SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff,
SYSC_MODULE_QUIRK_SGX),
+ SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0,
+ SYSC_MODULE_QUIRK_RTC_UNLOCK),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
@@ -1356,7 +1378,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0),
SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0),
- SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0, 0),
SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
@@ -1478,6 +1499,40 @@ static void sysc_post_reset_quirk_i2c(struct sysc *ddata)
sysc_clk_quirk_i2c(ddata, true);
}

+/* RTC on am3 and 4 needs to be unlocked and locked for sysconfig */
+static void sysc_quirk_rtc(struct sysc *ddata, bool lock)
+{
+ u32 val, kick0_val = 0, kick1_val = 0;
+ unsigned long flags;
+ int error;
+
+ if (!lock) {
+ kick0_val = 0x83e70b13;
+ kick1_val = 0x95a4f1e0;
+ }
+
+ local_irq_save(flags);
+ /* RTC_STATUS BUSY bit may stay active for 1/32768 seconds (~30 usec) */
+ error = readl_poll_timeout(ddata->module_va + 0x44, val,
+ !(val & BIT(0)), 100, 50);
+ if (error)
+ dev_warn(ddata->dev, "rtc busy timeout\n");
+ /* Now we have ~15 microseconds to read/write various registers */
+ sysc_write(ddata, 0x6c, kick0_val);
+ sysc_write(ddata, 0x70, kick1_val);
+ local_irq_restore(flags);
+}
+
+static void sysc_module_unlock_quirk_rtc(struct sysc *ddata)
+{
+ sysc_quirk_rtc(ddata, false);
+}
+
+static void sysc_module_lock_quirk_rtc(struct sysc *ddata)
+{
+ sysc_quirk_rtc(ddata, true);
+}
+
/* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */
static void sysc_module_enable_quirk_sgx(struct sysc *ddata)
{
@@ -1532,6 +1587,13 @@ static void sysc_init_module_quirks(struct sysc *ddata)
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS)
ddata->module_enable_quirk = sysc_module_enable_quirk_aess;

+ if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_RTC_UNLOCK) {
+ ddata->module_unlock_quirk = sysc_module_unlock_quirk_rtc;
+ ddata->module_lock_quirk = sysc_module_lock_quirk_rtc;
+
+ return;
+ }
+
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX)
ddata->module_enable_quirk = sysc_module_enable_quirk_sgx;

diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -49,6 +49,7 @@ struct sysc_regbits {
s8 emufree_shift;
};

+#define SYSC_MODULE_QUIRK_RTC_UNLOCK BIT(22)
#define SYSC_QUIRK_CLKDM_NOAUTO BIT(21)
#define SYSC_QUIRK_FORCE_MSTANDBY BIT(20)
#define SYSC_MODULE_QUIRK_AESS BIT(19)
--
2.25.1

2020-02-21 19:54:22

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 3/7] ti-sysc: Improve reset to work with modules with no sysconfig

At least display susbsystem (DSS) has modules with no sysconfig registers
and rely on custom function for module reset handling. Let's make reset
work with that too.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -1571,7 +1571,7 @@ static int sysc_reset(struct sysc *ddata)
sysc_offset = ddata->offsets[SYSC_SYSCONFIG];
syss_offset = ddata->offsets[SYSC_SYSSTATUS];

- if (ddata->legacy_mode || sysc_offset < 0 ||
+ if (ddata->legacy_mode ||
ddata->cap->regbits->srst_shift < 0 ||
ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)
return 0;
@@ -1586,9 +1586,11 @@ static int sysc_reset(struct sysc *ddata)
if (ddata->pre_reset_quirk)
ddata->pre_reset_quirk(ddata);

- sysc_val = sysc_read_sysconfig(ddata);
- sysc_val |= sysc_mask;
- sysc_write(ddata, sysc_offset, sysc_val);
+ if (sysc_offset >= 0) {
+ sysc_val = sysc_read_sysconfig(ddata);
+ sysc_val |= sysc_mask;
+ sysc_write(ddata, sysc_offset, sysc_val);
+ }

if (ddata->cfg.srst_udelay)
usleep_range(ddata->cfg.srst_udelay,
--
2.25.1

2020-02-21 19:54:26

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 5/7] bus: ti-sysc: Don't warn about legacy property for nested ti-sysc devices

In some cases we can have nested ti-sysc instances that may still use the
legacy "ti,hwmods" property. Let's not warn if that's the case.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/bus/ti-sysc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -624,7 +624,7 @@ static void sysc_check_one_child(struct sysc *ddata,
const char *name;

name = of_get_property(np, "ti,hwmods", NULL);
- if (name)
+ if (name && !of_device_is_compatible(np, "ti,sysc"))
dev_warn(ddata->dev, "really a child ti,hwmods property?");

sysc_check_quirk_stdout(ddata, np);
--
2.25.1

2020-02-21 19:54:55

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH 6/7] bus: ti-sysc: Implement SoC revision handling

We need to know SoC type and features for cases where the same SoC
may be installed in various versions on the same board and would need
a separate dts file otherwise for the different variants.

For example, am3703 is pin compatible with omap3630, but has sgx and
iva accelerators disabled. We must not try to access the sgx or iva
module registers on am3703, and need to set the unavailable devices
disabled early.

Let's also detect omap3430 as that is needed for display subsystem
(DSS) reset later on, and GP vs EMU or HS devices. Further SoC
specific disabled device detection can be added as needed, such as
dra71x vs dra76x rtc and usb4.

Cc: Adam Ford <[email protected]>
Cc: AndrĂ© Hentschel <[email protected]>
Cc: H. Nikolaus Schaller <[email protected]>
Cc: Keerthy <[email protected]>
Signed-off-by: Tony Lindgren <[email protected]>
---
arch/arm/mach-omap2/pdata-quirks.c | 6 +
drivers/bus/ti-sysc.c | 194 +++++++++++++++++++++++++-
include/linux/platform_data/ti-sysc.h | 1 +
3 files changed, 200 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -397,10 +397,16 @@ static int ti_sysc_shutdown_module(struct device *dev,
return omap_hwmod_shutdown(cookie->data);
}

+static bool ti_sysc_soc_type_gp(void)
+{
+ return omap_type() == OMAP2_DEVICE_TYPE_GP;
+}
+
static struct of_dev_auxdata omap_auxdata_lookup[];

static struct ti_sysc_platform_data ti_sysc_pdata = {
.auxdata = omap_auxdata_lookup,
+ .soc_type_gp = ti_sysc_soc_type_gp,
.init_clockdomain = ti_sysc_clkdm_init,
.clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
.clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -7,6 +7,7 @@
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/delay.h>
+#include <linux/list.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
@@ -15,15 +16,47 @@
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
+#include <linux/sys_soc.h>
#include <linux/iopoll.h>

#include <linux/platform_data/ti-sysc.h>

#include <dt-bindings/bus/ti-sysc.h>

+#define DIS_ISP BIT(2)
+#define DIS_IVA BIT(1)
+#define DIS_SGX BIT(0)
+
+#define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), }
+
#define MAX_MODULE_SOFTRESET_WAIT 10000

-static const char * const reg_names[] = { "rev", "sysc", "syss", };
+enum sysc_soc {
+ SOC_UNKNOWN,
+ SOC_2420,
+ SOC_2430,
+ SOC_3430,
+ SOC_3630,
+ SOC_4430,
+ SOC_4460,
+ SOC_4470,
+ SOC_5430,
+ SOC_AM3,
+ SOC_AM4,
+ SOC_DRA7,
+};
+
+struct sysc_address {
+ unsigned long base;
+ struct list_head node;
+};
+
+struct sysc_soc_info {
+ unsigned long general_purpose:1;
+ enum sysc_soc soc;
+ struct mutex list_lock; /* disabled modules list lock */
+ struct list_head disabled_modules;
+};

enum sysc_clocks {
SYSC_FCK,
@@ -39,6 +72,8 @@ enum sysc_clocks {
SYSC_MAX_CLOCKS,
};

+static struct sysc_soc_info *sysc_soc;
+static const char * const reg_names[] = { "rev", "sysc", "syss", };
static const char * const clock_names[SYSC_MAX_CLOCKS] = {
"fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4",
"opt5", "opt6", "opt7",
@@ -2382,6 +2417,154 @@ static void ti_sysc_idle(struct work_struct *work)
pm_runtime_put_sync(ddata->dev);
}

+/*
+ * SoC model and features detection. Only needed for SoCs that need
+ * special handling for quirks, no need to list others.
+ */
+static const struct soc_device_attribute sysc_soc_match[] = {
+ SOC_FLAG("OMAP242*", SOC_2420),
+ SOC_FLAG("OMAP243*", SOC_2430),
+ SOC_FLAG("OMAP3[45]*", SOC_3430),
+ SOC_FLAG("OMAP3[67]*", SOC_3630),
+ SOC_FLAG("OMAP443*", SOC_4430),
+ SOC_FLAG("OMAP446*", SOC_4460),
+ SOC_FLAG("OMAP447*", SOC_4470),
+ SOC_FLAG("OMAP54*", SOC_5430),
+ SOC_FLAG("AM433", SOC_AM3),
+ SOC_FLAG("AM43*", SOC_AM4),
+ SOC_FLAG("DRA7*", SOC_DRA7),
+
+ { /* sentinel */ },
+};
+
+/*
+ * List of SoCs variants with disabled features. By default we assume all
+ * devices in the device tree are available so no need to list those SoCs.
+ */
+static const struct soc_device_attribute sysc_soc_feat_match[] = {
+ /* OMAP3430/3530 and AM3517 variants with some accelerators disabled */
+ SOC_FLAG("AM3505", DIS_SGX),
+ SOC_FLAG("OMAP3525", DIS_SGX),
+ SOC_FLAG("OMAP3515", DIS_IVA | DIS_SGX),
+ SOC_FLAG("OMAP3503", DIS_ISP | DIS_IVA | DIS_SGX),
+
+ /* OMAP3630/DM3730 variants with some accelerators disabled */
+ SOC_FLAG("AM3703", DIS_IVA | DIS_SGX),
+ SOC_FLAG("DM3725", DIS_SGX),
+ SOC_FLAG("OMAP3611", DIS_ISP | DIS_IVA | DIS_SGX),
+ SOC_FLAG("OMAP3615/AM3715", DIS_IVA),
+ SOC_FLAG("OMAP3621", DIS_ISP),
+
+ { /* sentinel */ },
+};
+
+static int sysc_add_disabled(unsigned long base)
+{
+ struct sysc_address *disabled_module;
+
+ disabled_module = kzalloc(sizeof(*disabled_module), GFP_KERNEL);
+ if (!disabled_module)
+ return -ENOMEM;
+
+ disabled_module->base = base;
+
+ mutex_lock(&sysc_soc->list_lock);
+ list_add(&disabled_module->node, &sysc_soc->disabled_modules);
+ mutex_unlock(&sysc_soc->list_lock);
+
+ return 0;
+}
+
+/*
+ * One time init to detect the booted SoC and disable unavailable features.
+ * Note that we initialize static data shared across all ti-sysc instances
+ * so ddata is only used for SoC type. This can be called from module_init
+ * once we no longer need to rely on platform data.
+ */
+static int sysc_init_soc(struct sysc *ddata)
+{
+ const struct soc_device_attribute *match;
+ struct ti_sysc_platform_data *pdata;
+ unsigned long features = 0;
+
+ if (sysc_soc)
+ return 0;
+
+ sysc_soc = kzalloc(sizeof(*sysc_soc), GFP_KERNEL);
+ if (!sysc_soc)
+ return -ENOMEM;
+
+ mutex_init(&sysc_soc->list_lock);
+ INIT_LIST_HEAD(&sysc_soc->disabled_modules);
+ sysc_soc->general_purpose = true;
+
+ pdata = dev_get_platdata(ddata->dev);
+ if (pdata && pdata->soc_type_gp)
+ sysc_soc->general_purpose = pdata->soc_type_gp();
+
+ match = soc_device_match(sysc_soc_match);
+ if (match && match->data)
+ sysc_soc->soc = (int)match->data;
+
+ match = soc_device_match(sysc_soc_feat_match);
+ if (!match)
+ return 0;
+
+ if (match->data)
+ features = (unsigned long)match->data;
+
+ /*
+ * Add disabled devices to the list based on the module base.
+ * Note that this must be done before we attempt to access the
+ * device and have module revision checks working.
+ */
+ if (features & DIS_ISP)
+ sysc_add_disabled(0x480bd400);
+ if (features & DIS_IVA)
+ sysc_add_disabled(0x5d000000);
+ if (features & DIS_SGX)
+ sysc_add_disabled(0x50000000);
+
+ return 0;
+}
+
+static void sysc_cleanup_soc(void)
+{
+ struct sysc_address *disabled_module;
+ struct list_head *pos, *tmp;
+
+ if (!sysc_soc)
+ return;
+
+ mutex_lock(&sysc_soc->list_lock);
+ list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) {
+ disabled_module = list_entry(pos, struct sysc_address, node);
+ list_del(pos);
+ kfree(disabled_module);
+ }
+ mutex_unlock(&sysc_soc->list_lock);
+}
+
+static int sysc_check_disabled_devices(struct sysc *ddata)
+{
+ struct sysc_address *disabled_module;
+ struct list_head *pos;
+ int error = 0;
+
+ mutex_lock(&sysc_soc->list_lock);
+ list_for_each(pos, &sysc_soc->disabled_modules) {
+ disabled_module = list_entry(pos, struct sysc_address, node);
+ if (ddata->module_pa == disabled_module->base) {
+ dev_dbg(ddata->dev, "module disabled for this SoC\n");
+ error = -ENODEV;
+ break;
+ }
+ }
+ mutex_unlock(&sysc_soc->list_lock);
+
+ return error;
+}
+
static const struct of_device_id sysc_match_table[] = {
{ .compatible = "simple-bus", },
{ /* sentinel */ },
@@ -2400,6 +2583,10 @@ static int sysc_probe(struct platform_device *pdev)
ddata->dev = &pdev->dev;
platform_set_drvdata(pdev, ddata);

+ error = sysc_init_soc(ddata);
+ if (error)
+ return error;
+
error = sysc_init_match(ddata);
if (error)
return error;
@@ -2430,6 +2617,10 @@ static int sysc_probe(struct platform_device *pdev)

sysc_init_early_quirks(ddata);

+ error = sysc_check_disabled_devices(ddata);
+ if (error)
+ return error;
+
error = sysc_get_clocks(ddata);
if (error)
return error;
@@ -2560,6 +2751,7 @@ static void __exit sysc_exit(void)
{
bus_unregister_notifier(&platform_bus_type, &sysc_nb);
platform_driver_unregister(&sysc_driver);
+ sysc_cleanup_soc();
}
module_exit(sysc_exit);

diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
--- a/include/linux/platform_data/ti-sysc.h
+++ b/include/linux/platform_data/ti-sysc.h
@@ -141,6 +141,7 @@ struct clk;

struct ti_sysc_platform_data {
struct of_dev_auxdata *auxdata;
+ bool (*soc_type_gp)(void);
int (*init_clockdomain)(struct device *dev, struct clk *fck,
struct clk *ick, struct ti_sysc_cookie *cookie);
void (*clkdm_deny_idle)(struct device *dev,
--
2.25.1

2022-03-02 20:08:44

by Adam Ford

[permalink] [raw]
Subject: Re: [PATCH 6/7] bus: ti-sysc: Implement SoC revision handling

On Fri, Feb 21, 2020 at 1:53 PM Tony Lindgren <[email protected]> wrote:
>
> We need to know SoC type and features for cases where the same SoC
> may be installed in various versions on the same board and would need
> a separate dts file otherwise for the different variants.
>
> For example, am3703 is pin compatible with omap3630, but has sgx and
> iva accelerators disabled. We must not try to access the sgx or iva
> module registers on am3703, and need to set the unavailable devices
> disabled early.
>
> Let's also detect omap3430 as that is needed for display subsystem
> (DSS) reset later on, and GP vs EMU or HS devices. Further SoC
> specific disabled device detection can be added as needed, such as
> dra71x vs dra76x rtc and usb4.
>
> Cc: Adam Ford <[email protected]>
> Cc: AndrĂ© Hentschel <[email protected]>
> Cc: H. Nikolaus Schaller <[email protected]>
> Cc: Keerthy <[email protected]>
> Signed-off-by: Tony Lindgren <[email protected]>

Tony,

I apologize for digging up an old thread, but I finally managed to get
my hands on an OMAP3503. It seems like older kernels do not boot at
all or hang somewhere in the boot process. I am still seeing a
difference in behavior between OMAP3503 and OMAP3530, where 3505
throws a bunch of splat and a kernel panic, while the 3530 appears to
boot happily.

Using the latest 5.17-rc6, I had to remove some IVA and SGX references
from omap_l3_smx.h to get the 3503 to stop crashing on boot.

Do you have any ideas how we can make the omap3_l3_app_bases and
omap3_l3_debug_bases more cleanly remove the IVA and SGX references
if/when OMAP3503 is detected? I assume the same algorithm would have
to detect a AM3703 as well. I'm trying to get my hands on an AM3703
to see if there is similar behavior as what I'm seeing on the
OMAP3503.

Thanks,

adam

> ---
> arch/arm/mach-omap2/pdata-quirks.c | 6 +
> drivers/bus/ti-sysc.c | 194 +++++++++++++++++++++++++-
> include/linux/platform_data/ti-sysc.h | 1 +
> 3 files changed, 200 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
> --- a/arch/arm/mach-omap2/pdata-quirks.c
> +++ b/arch/arm/mach-omap2/pdata-quirks.c
> @@ -397,10 +397,16 @@ static int ti_sysc_shutdown_module(struct device *dev,
> return omap_hwmod_shutdown(cookie->data);
> }
>
> +static bool ti_sysc_soc_type_gp(void)
> +{
> + return omap_type() == OMAP2_DEVICE_TYPE_GP;
> +}
> +
> static struct of_dev_auxdata omap_auxdata_lookup[];
>
> static struct ti_sysc_platform_data ti_sysc_pdata = {
> .auxdata = omap_auxdata_lookup,
> + .soc_type_gp = ti_sysc_soc_type_gp,
> .init_clockdomain = ti_sysc_clkdm_init,
> .clkdm_deny_idle = ti_sysc_clkdm_deny_idle,
> .clkdm_allow_idle = ti_sysc_clkdm_allow_idle,
> diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
> --- a/drivers/bus/ti-sysc.c
> +++ b/drivers/bus/ti-sysc.c
> @@ -7,6 +7,7 @@
> #include <linux/clk.h>
> #include <linux/clkdev.h>
> #include <linux/delay.h>
> +#include <linux/list.h>
> #include <linux/module.h>
> #include <linux/platform_device.h>
> #include <linux/pm_domain.h>
> @@ -15,15 +16,47 @@
> #include <linux/of_address.h>
> #include <linux/of_platform.h>
> #include <linux/slab.h>
> +#include <linux/sys_soc.h>
> #include <linux/iopoll.h>
>
> #include <linux/platform_data/ti-sysc.h>
>
> #include <dt-bindings/bus/ti-sysc.h>
>
> +#define DIS_ISP BIT(2)
> +#define DIS_IVA BIT(1)
> +#define DIS_SGX BIT(0)
> +
> +#define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), }
> +
> #define MAX_MODULE_SOFTRESET_WAIT 10000
>
> -static const char * const reg_names[] = { "rev", "sysc", "syss", };
> +enum sysc_soc {
> + SOC_UNKNOWN,
> + SOC_2420,
> + SOC_2430,
> + SOC_3430,
> + SOC_3630,
> + SOC_4430,
> + SOC_4460,
> + SOC_4470,
> + SOC_5430,
> + SOC_AM3,
> + SOC_AM4,
> + SOC_DRA7,
> +};
> +
> +struct sysc_address {
> + unsigned long base;
> + struct list_head node;
> +};
> +
> +struct sysc_soc_info {
> + unsigned long general_purpose:1;
> + enum sysc_soc soc;
> + struct mutex list_lock; /* disabled modules list lock */
> + struct list_head disabled_modules;
> +};
>
> enum sysc_clocks {
> SYSC_FCK,
> @@ -39,6 +72,8 @@ enum sysc_clocks {
> SYSC_MAX_CLOCKS,
> };
>
> +static struct sysc_soc_info *sysc_soc;
> +static const char * const reg_names[] = { "rev", "sysc", "syss", };
> static const char * const clock_names[SYSC_MAX_CLOCKS] = {
> "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4",
> "opt5", "opt6", "opt7",
> @@ -2382,6 +2417,154 @@ static void ti_sysc_idle(struct work_struct *work)
> pm_runtime_put_sync(ddata->dev);
> }
>
> +/*
> + * SoC model and features detection. Only needed for SoCs that need
> + * special handling for quirks, no need to list others.
> + */
> +static const struct soc_device_attribute sysc_soc_match[] = {
> + SOC_FLAG("OMAP242*", SOC_2420),
> + SOC_FLAG("OMAP243*", SOC_2430),
> + SOC_FLAG("OMAP3[45]*", SOC_3430),
> + SOC_FLAG("OMAP3[67]*", SOC_3630),
> + SOC_FLAG("OMAP443*", SOC_4430),
> + SOC_FLAG("OMAP446*", SOC_4460),
> + SOC_FLAG("OMAP447*", SOC_4470),
> + SOC_FLAG("OMAP54*", SOC_5430),
> + SOC_FLAG("AM433", SOC_AM3),
> + SOC_FLAG("AM43*", SOC_AM4),
> + SOC_FLAG("DRA7*", SOC_DRA7),
> +
> + { /* sentinel */ },
> +};
> +
> +/*
> + * List of SoCs variants with disabled features. By default we assume all
> + * devices in the device tree are available so no need to list those SoCs.
> + */
> +static const struct soc_device_attribute sysc_soc_feat_match[] = {
> + /* OMAP3430/3530 and AM3517 variants with some accelerators disabled */
> + SOC_FLAG("AM3505", DIS_SGX),
> + SOC_FLAG("OMAP3525", DIS_SGX),
> + SOC_FLAG("OMAP3515", DIS_IVA | DIS_SGX),
> + SOC_FLAG("OMAP3503", DIS_ISP | DIS_IVA | DIS_SGX),
> +
> + /* OMAP3630/DM3730 variants with some accelerators disabled */
> + SOC_FLAG("AM3703", DIS_IVA | DIS_SGX),
> + SOC_FLAG("DM3725", DIS_SGX),
> + SOC_FLAG("OMAP3611", DIS_ISP | DIS_IVA | DIS_SGX),
> + SOC_FLAG("OMAP3615/AM3715", DIS_IVA),
> + SOC_FLAG("OMAP3621", DIS_ISP),
> +
> + { /* sentinel */ },
> +};
> +
> +static int sysc_add_disabled(unsigned long base)
> +{
> + struct sysc_address *disabled_module;
> +
> + disabled_module = kzalloc(sizeof(*disabled_module), GFP_KERNEL);
> + if (!disabled_module)
> + return -ENOMEM;
> +
> + disabled_module->base = base;
> +
> + mutex_lock(&sysc_soc->list_lock);
> + list_add(&disabled_module->node, &sysc_soc->disabled_modules);
> + mutex_unlock(&sysc_soc->list_lock);
> +
> + return 0;
> +}
> +
> +/*
> + * One time init to detect the booted SoC and disable unavailable features.
> + * Note that we initialize static data shared across all ti-sysc instances
> + * so ddata is only used for SoC type. This can be called from module_init
> + * once we no longer need to rely on platform data.
> + */
> +static int sysc_init_soc(struct sysc *ddata)
> +{
> + const struct soc_device_attribute *match;
> + struct ti_sysc_platform_data *pdata;
> + unsigned long features = 0;
> +
> + if (sysc_soc)
> + return 0;
> +
> + sysc_soc = kzalloc(sizeof(*sysc_soc), GFP_KERNEL);
> + if (!sysc_soc)
> + return -ENOMEM;
> +
> + mutex_init(&sysc_soc->list_lock);
> + INIT_LIST_HEAD(&sysc_soc->disabled_modules);
> + sysc_soc->general_purpose = true;
> +
> + pdata = dev_get_platdata(ddata->dev);
> + if (pdata && pdata->soc_type_gp)
> + sysc_soc->general_purpose = pdata->soc_type_gp();
> +
> + match = soc_device_match(sysc_soc_match);
> + if (match && match->data)
> + sysc_soc->soc = (int)match->data;
> +
> + match = soc_device_match(sysc_soc_feat_match);
> + if (!match)
> + return 0;
> +
> + if (match->data)
> + features = (unsigned long)match->data;
> +
> + /*
> + * Add disabled devices to the list based on the module base.
> + * Note that this must be done before we attempt to access the
> + * device and have module revision checks working.
> + */
> + if (features & DIS_ISP)
> + sysc_add_disabled(0x480bd400);
> + if (features & DIS_IVA)
> + sysc_add_disabled(0x5d000000);
> + if (features & DIS_SGX)
> + sysc_add_disabled(0x50000000);
> +
> + return 0;
> +}
> +
> +static void sysc_cleanup_soc(void)
> +{
> + struct sysc_address *disabled_module;
> + struct list_head *pos, *tmp;
> +
> + if (!sysc_soc)
> + return;
> +
> + mutex_lock(&sysc_soc->list_lock);
> + list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) {
> + disabled_module = list_entry(pos, struct sysc_address, node);
> + list_del(pos);
> + kfree(disabled_module);
> + }
> + mutex_unlock(&sysc_soc->list_lock);
> +}
> +
> +static int sysc_check_disabled_devices(struct sysc *ddata)
> +{
> + struct sysc_address *disabled_module;
> + struct list_head *pos;
> + int error = 0;
> +
> + mutex_lock(&sysc_soc->list_lock);
> + list_for_each(pos, &sysc_soc->disabled_modules) {
> + disabled_module = list_entry(pos, struct sysc_address, node);
> + if (ddata->module_pa == disabled_module->base) {
> + dev_dbg(ddata->dev, "module disabled for this SoC\n");
> + error = -ENODEV;
> + break;
> + }
> + }
> + mutex_unlock(&sysc_soc->list_lock);
> +
> + return error;
> +}
> +
> static const struct of_device_id sysc_match_table[] = {
> { .compatible = "simple-bus", },
> { /* sentinel */ },
> @@ -2400,6 +2583,10 @@ static int sysc_probe(struct platform_device *pdev)
> ddata->dev = &pdev->dev;
> platform_set_drvdata(pdev, ddata);
>
> + error = sysc_init_soc(ddata);
> + if (error)
> + return error;
> +
> error = sysc_init_match(ddata);
> if (error)
> return error;
> @@ -2430,6 +2617,10 @@ static int sysc_probe(struct platform_device *pdev)
>
> sysc_init_early_quirks(ddata);
>
> + error = sysc_check_disabled_devices(ddata);
> + if (error)
> + return error;
> +
> error = sysc_get_clocks(ddata);
> if (error)
> return error;
> @@ -2560,6 +2751,7 @@ static void __exit sysc_exit(void)
> {
> bus_unregister_notifier(&platform_bus_type, &sysc_nb);
> platform_driver_unregister(&sysc_driver);
> + sysc_cleanup_soc();
> }
> module_exit(sysc_exit);
>
> diff --git a/include/linux/platform_data/ti-sysc.h b/include/linux/platform_data/ti-sysc.h
> --- a/include/linux/platform_data/ti-sysc.h
> +++ b/include/linux/platform_data/ti-sysc.h
> @@ -141,6 +141,7 @@ struct clk;
>
> struct ti_sysc_platform_data {
> struct of_dev_auxdata *auxdata;
> + bool (*soc_type_gp)(void);
> int (*init_clockdomain)(struct device *dev, struct clk *fck,
> struct clk *ick, struct ti_sysc_cookie *cookie);
> void (*clkdm_deny_idle)(struct device *dev,
> --
> 2.25.1

2022-03-04 09:06:42

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH 6/7] bus: ti-sysc: Implement SoC revision handling

Hi,

* Adam Ford <[email protected]> [220302 14:37]:
> I apologize for digging up an old thread, but I finally managed to get
> my hands on an OMAP3503. It seems like older kernels do not boot at
> all or hang somewhere in the boot process. I am still seeing a
> difference in behavior between OMAP3503 and OMAP3530, where 3505
> throws a bunch of splat and a kernel panic, while the 3530 appears to
> boot happily.
>
> Using the latest 5.17-rc6, I had to remove some IVA and SGX references
> from omap_l3_smx.h to get the 3503 to stop crashing on boot.

OK interesting, I did not know those registers are not accessible
on 3503.

> Do you have any ideas how we can make the omap3_l3_app_bases and
> omap3_l3_debug_bases more cleanly remove the IVA and SGX references
> if/when OMAP3503 is detected? I assume the same algorithm would have
> to detect a AM3703 as well. I'm trying to get my hands on an AM3703
> to see if there is similar behavior as what I'm seeing on the
> OMAP3503.

As there are possibly multiple omap3 variants used on the same
boards, we need to rely on the runtime detection of the SoC.
So yeah soc_device_attribute is the way to go here.

I don't recall any similar issues booting 3703 but it's been a while
so worth testing for sure.

Regards,

Tony

2022-03-04 18:29:24

by Adam Ford

[permalink] [raw]
Subject: Re: [PATCH 6/7] bus: ti-sysc: Implement SoC revision handling

On Fri, Mar 4, 2022 at 12:57 AM Tony Lindgren <[email protected]> wrote:
>
> Hi,
>
> * Adam Ford <[email protected]> [220302 14:37]:
> > I apologize for digging up an old thread, but I finally managed to get
> > my hands on an OMAP3503. It seems like older kernels do not boot at
> > all or hang somewhere in the boot process. I am still seeing a
> > difference in behavior between OMAP3503 and OMAP3530, where 3505
> > throws a bunch of splat and a kernel panic, while the 3530 appears to
> > boot happily.
> >
> > Using the latest 5.17-rc6, I had to remove some IVA and SGX references
> > from omap_l3_smx.h to get the 3503 to stop crashing on boot.
>
> OK interesting, I did not know those registers are not accessible
> on 3503.
>
> > Do you have any ideas how we can make the omap3_l3_app_bases and
> > omap3_l3_debug_bases more cleanly remove the IVA and SGX references
> > if/when OMAP3503 is detected? I assume the same algorithm would have
> > to detect a AM3703 as well. I'm trying to get my hands on an AM3703
> > to see if there is similar behavior as what I'm seeing on the
> > OMAP3503.
>
> As there are possibly multiple omap3 variants used on the same
> boards, we need to rely on the runtime detection of the SoC.
> So yeah soc_device_attribute is the way to go here.
>
> I don't recall any similar issues booting 3703 but it's been a while
> so worth testing for sure.

In addition to the OMAP3503, I managed to get an AM3703. From what I
can tell, going back as far as kernel 4.9, the OMAP3503 does not boot
at all. I haven't tried the 4.4 since it's marked EOL at this point.

I have not started testing the AM3703 yet, but I think it would be a
good idea to backport this to stable at some point, since it appears
to fix a serious regression, not booting. I'm going to work on some
experiments with both the AM3703 and OMAP3503 to see what works, what
doesn't and I'm going try to come up with some ideas on how to address
the omap3_l3_app changes, but if you have any ideas on how to do it
cleanly, I'm open for suggestions.

adam
>
> Regards,
>
> Tony