Commit e8639e1c authored by Tony Lindgren's avatar Tony Lindgren

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: default avatarTony Lindgren <tony@atomide.com>
parent feaa8bae
...@@ -110,6 +110,8 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { ...@@ -110,6 +110,8 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = {
* @reset_done_quirk: module specific reset done quirk * @reset_done_quirk: module specific reset done quirk
* @module_enable_quirk: module specific enable quirk * @module_enable_quirk: module specific enable quirk
* @module_disable_quirk: module specific disable 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 sysc {
struct device *dev; struct device *dev;
...@@ -137,6 +139,8 @@ struct sysc { ...@@ -137,6 +139,8 @@ struct sysc {
void (*reset_done_quirk)(struct sysc *sysc); void (*reset_done_quirk)(struct sysc *sysc);
void (*module_enable_quirk)(struct sysc *sysc); void (*module_enable_quirk)(struct sysc *sysc);
void (*module_disable_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, 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) ...@@ -896,6 +900,22 @@ static void sysc_show_registers(struct sysc *ddata)
buf); 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_IDLE_MASK (SYSC_NR_IDLEMODES - 1)
#define SYSC_CLOCACT_ICK 2 #define SYSC_CLOCACT_ICK 2
...@@ -942,7 +962,7 @@ static int sysc_enable_module(struct device *dev) ...@@ -942,7 +962,7 @@ static int sysc_enable_module(struct device *dev)
reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift);
reg |= best_mode << 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:
/* Set MIDLE mode */ /* Set MIDLE mode */
...@@ -961,14 +981,14 @@ static int sysc_enable_module(struct device *dev) ...@@ -961,14 +981,14 @@ static int sysc_enable_module(struct device *dev)
reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
reg |= best_mode << regbits->midle_shift; reg |= best_mode << regbits->midle_shift;
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); sysc_write_sysconfig(ddata, reg);
set_autoidle: set_autoidle:
/* Autoidle bit must enabled separately if available */ /* Autoidle bit must enabled separately if available */
if (regbits->autoidle_shift >= 0 && if (regbits->autoidle_shift >= 0 &&
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) { ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) {
reg |= 1 << 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) if (ddata->module_enable_quirk)
...@@ -1026,7 +1046,7 @@ static int sysc_disable_module(struct device *dev) ...@@ -1026,7 +1046,7 @@ static int sysc_disable_module(struct device *dev)
reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift);
reg |= best_mode << 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:
/* Set SIDLE mode */ /* Set SIDLE mode */
...@@ -1049,7 +1069,7 @@ static int sysc_disable_module(struct device *dev) ...@@ -1049,7 +1069,7 @@ static int sysc_disable_module(struct device *dev)
if (regbits->autoidle_shift >= 0 && if (regbits->autoidle_shift >= 0 &&
ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) ddata->cfg.sysc_val & BIT(regbits->autoidle_shift))
reg |= 1 << regbits->autoidle_shift; reg |= 1 << regbits->autoidle_shift;
sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); sysc_write_sysconfig(ddata, reg);
return 0; return 0;
} }
...@@ -1301,6 +1321,8 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { ...@@ -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, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0),
SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff,
SYSC_MODULE_QUIRK_SGX), 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, SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY),
SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff, SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff,
...@@ -1356,7 +1378,6 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { ...@@ -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("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0),
SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0), SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0),
SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 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("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, 0x00000004, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 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) ...@@ -1478,6 +1499,40 @@ static void sysc_post_reset_quirk_i2c(struct sysc *ddata)
sysc_clk_quirk_i2c(ddata, true); 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 */ /* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */
static void sysc_module_enable_quirk_sgx(struct sysc *ddata) static void sysc_module_enable_quirk_sgx(struct sysc *ddata)
{ {
...@@ -1532,6 +1587,13 @@ static void sysc_init_module_quirks(struct sysc *ddata) ...@@ -1532,6 +1587,13 @@ static void sysc_init_module_quirks(struct sysc *ddata)
if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS) if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS)
ddata->module_enable_quirk = sysc_module_enable_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) if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX)
ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; ddata->module_enable_quirk = sysc_module_enable_quirk_sgx;
......
...@@ -49,6 +49,7 @@ struct sysc_regbits { ...@@ -49,6 +49,7 @@ struct sysc_regbits {
s8 emufree_shift; s8 emufree_shift;
}; };
#define SYSC_MODULE_QUIRK_RTC_UNLOCK BIT(22)
#define SYSC_QUIRK_CLKDM_NOAUTO BIT(21) #define SYSC_QUIRK_CLKDM_NOAUTO BIT(21)
#define SYSC_QUIRK_FORCE_MSTANDBY BIT(20) #define SYSC_QUIRK_FORCE_MSTANDBY BIT(20)
#define SYSC_MODULE_QUIRK_AESS BIT(19) #define SYSC_MODULE_QUIRK_AESS BIT(19)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment