From 0a5fdaadc4a535cfb693d98738fde8d48b77447f Mon Sep 17 00:00:00 2001 From: Vladimir Barinov Date: Wed, 7 Feb 2018 19:38:59 +0300 Subject: V3M/V3H: sysc workaround for power down, cpu clock fixup This adds SYSC workaround for power domains power down sequence on V3M/V3H and add cpu clock fixup on V3H. Also add VisionIP nodes and fix VSP i/f on V3H --- ...-rcar-sysc-Add-workaround-for-A3-PD-issue.patch | 278 +++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0052-soc-renesas-rcar-sysc-Add-workaround-for-A3-PD-issue.patch (limited to 'meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0052-soc-renesas-rcar-sysc-Add-workaround-for-A3-PD-issue.patch') diff --git a/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0052-soc-renesas-rcar-sysc-Add-workaround-for-A3-PD-issue.patch b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0052-soc-renesas-rcar-sysc-Add-workaround-for-A3-PD-issue.patch new file mode 100644 index 0000000..9cad500 --- /dev/null +++ b/meta-rcar-gen3-adas/recipes-kernel/linux/linux-renesas/0052-soc-renesas-rcar-sysc-Add-workaround-for-A3-PD-issue.patch @@ -0,0 +1,278 @@ +From 01fdcd06bd73807c03a6c8cf077fa53841861b58 Mon Sep 17 00:00:00 2001 +From: Shinyu Ninomiya +Date: Fri, 26 Jan 2018 21:38:58 +0900 +Subject: [PATCH] soc: renesas: rcar-sysc: Add workaround for A3 PD issue + +Before turning ON/OFF power domain of A3VIP0, A3VIP1, A3VIP2 the clock is supplied for BoschIP +by deactivating MSTP assigned for BoschIP before. This issue is also occurred at A3IR. +MSTP for impdes0 and impc0 should be deactivated before turning off A3IR domain. +This implements workaround to implement the sequence above. + +Signed-off-by: Shinyu Ninomiya +--- + drivers/soc/renesas/r8a7797-sysc.c | 3 +- + drivers/soc/renesas/r8a7798-sysc.c | 12 +++-- + drivers/soc/renesas/rcar-sysc.c | 108 ++++++++++++++++++++++++++++++++++++- + drivers/soc/renesas/rcar-sysc.h | 6 +++ + 4 files changed, 123 insertions(+), 6 deletions(-) + +diff --git a/drivers/soc/renesas/r8a7797-sysc.c b/drivers/soc/renesas/r8a7797-sysc.c +index cde7d9e..5725ad0 100644 +--- a/drivers/soc/renesas/r8a7797-sysc.c ++++ b/drivers/soc/renesas/r8a7797-sysc.c +@@ -24,7 +24,8 @@ static const struct rcar_sysc_area r8a7797_areas[] __initconst = { + { "ca53-cpu1", 0x200, 1, R8A7797_PD_CA53_CPU1, R8A7797_PD_CA53_SCU, + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A7797_PD_CR7, R8A7797_PD_ALWAYS_ON }, +- { "a3ir", 0x180, 0, R8A7797_PD_A3IR, R8A7797_PD_ALWAYS_ON }, ++ { "a3ir", 0x180, 0, R8A7797_PD_A3IR, R8A7797_PD_ALWAYS_ON, ++ PD_WA_CLK, {"impram"} }, + { "a2ir0", 0x400, 0, R8A7797_PD_A2IR0, R8A7797_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A7797_PD_A2IR1, R8A7797_PD_A3IR }, + { "a2ir2", 0x400, 2, R8A7797_PD_A2IR2, R8A7797_PD_A3IR }, +diff --git a/drivers/soc/renesas/r8a7798-sysc.c b/drivers/soc/renesas/r8a7798-sysc.c +index 128e79d..2affaa2 100644 +--- a/drivers/soc/renesas/r8a7798-sysc.c ++++ b/drivers/soc/renesas/r8a7798-sysc.c +@@ -30,7 +30,8 @@ static const struct rcar_sysc_area r8a7798_areas[] __initconst = { + PD_CPU_NOCR }, + { "cr7", 0x240, 0, R8A7798_PD_CR7, R8A7798_PD_ALWAYS_ON }, + +- { "a3ir", 0x180, 0, R8A7798_PD_A3IR, R8A7798_PD_ALWAYS_ON }, ++ { "a3ir", 0x180, 0, R8A7798_PD_A3IR, R8A7798_PD_ALWAYS_ON, ++ PD_WA_CLK, {"impram"} }, + { "a2ir0", 0x400, 0, R8A7798_PD_A2IR0, R8A7798_PD_A3IR }, + { "a2ir1", 0x400, 1, R8A7798_PD_A2IR1, R8A7798_PD_A3IR }, + { "a2ir2", 0x400, 2, R8A7798_PD_A2IR2, R8A7798_PD_A3IR }, +@@ -46,9 +47,12 @@ static const struct rcar_sysc_area r8a7798_areas[] __initconst = { + { "a2pd1", 0x400, 12, R8A7798_PD_A2PD1, R8A7798_PD_A3IR }, + { "a2cn", 0x400, 13, R8A7798_PD_A2CN, R8A7798_PD_A3IR }, + +- { "a3vip", 0x2c0, 0, R8A7798_PD_A3VIP, R8A7798_PD_ALWAYS_ON }, +- { "a3vip1", 0x300, 0, R8A7798_PD_A3VIP1, R8A7798_PD_ALWAYS_ON }, +- { "a3vip2", 0x280, 0, R8A7798_PD_A3VIP2, R8A7798_PD_ALWAYS_ON }, ++ { "a3vip", 0x2c0, 0, R8A7798_PD_A3VIP, R8A7798_PD_ALWAYS_ON, ++ PD_WA_CLK, {"disp"} }, ++ { "a3vip1", 0x300, 0, R8A7798_PD_A3VIP1, R8A7798_PD_ALWAYS_ON, ++ PD_WA_CLK, {"umf", "smd_post", "smd_est", "smd_ps"} }, ++ { "a3vip2", 0x280, 0, R8A7798_PD_A3VIP2, R8A7798_PD_ALWAYS_ON, ++ PD_WA_CLK, {"cle0", "cle1", "cle2", "cle3", "cle4"} }, + }; + + const struct rcar_sysc_info r8a7798_sysc_info __initconst = { +diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c +index bfde184..f3f18d0 100644 +--- a/drivers/soc/renesas/rcar-sysc.c ++++ b/drivers/soc/renesas/rcar-sysc.c +@@ -20,6 +20,8 @@ + #include + #include + #include ++#include ++#include + + #include "rcar-sysc.h" + +@@ -64,6 +66,7 @@ static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ + + + static const char *to_pd_name(const struct rcar_sysc_ch *sysc_ch); ++static int rcar_sysc_wa_clk(const struct rcar_sysc_ch *sysc_ch, int en); + + static int rcar_sysc_pwr_on_off(const struct rcar_sysc_ch *sysc_ch, bool on) + { +@@ -110,6 +113,12 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) + int ret = 0; + int k; + ++ ret = rcar_sysc_wa_clk(sysc_ch, 1); ++ if (ret) { ++ pr_err("%s: Failed to enable clock for workaround\n", to_pd_name(sysc_ch)); ++ return ret; ++ } ++ + spin_lock_irqsave(&rcar_sysc_lock, flags); + + iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); +@@ -148,6 +157,8 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) + out: + spin_unlock_irqrestore(&rcar_sysc_lock, flags); + ++ rcar_sysc_wa_clk(sysc_ch, 0); ++ + pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", + sysc_ch->isr_bit, ioread32(rcar_sysc_base + SYSCISR), ret); + return ret; +@@ -178,9 +189,35 @@ struct rcar_sysc_pd { + struct generic_pm_domain genpd; + struct rcar_sysc_ch ch; + unsigned int flags; ++ struct clk *wa_clk[RCAR_SYSC_MAX_WA_CLKS]; + char name[0]; + }; + ++static int rcar_sysc_wa_clk(const struct rcar_sysc_ch *sysc_ch, int en) ++{ ++ int i, ret; ++ struct rcar_sysc_pd *pd = container_of(sysc_ch, struct rcar_sysc_pd, ch); ++ ++ if (pd->flags & PD_WA_CLK) { ++ if (!(pd->flags & PD_WA_CLK_RDY)) ++ return -EBUSY; ++ ++ for (i = 0; i < RCAR_SYSC_MAX_WA_CLKS; i++) { ++ if (!pd->wa_clk[i]) ++ break; ++ ++ if (en) { ++ ret = clk_enable(pd->wa_clk[i]); ++ if (ret) ++ return ret; ++ } else ++ clk_disable(pd->wa_clk[i]); ++ } ++ } ++ ++ return 0; ++} ++ + static inline struct rcar_sysc_pd *to_rcar_pd(struct generic_pm_domain *d) + { + return container_of(d, struct rcar_sysc_pd, genpd); +@@ -231,6 +268,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) + struct generic_pm_domain *genpd = &pd->genpd; + const char *name = pd->genpd.name; + struct dev_power_governor *gov = &simple_qos_governor; ++ bool is_off = false; + + if (pd->flags & PD_CPU) { + /* +@@ -278,6 +316,12 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) + goto finalize; + } + ++ if (pd->flags & PD_NO_INIT_ON) { ++ is_off = rcar_sysc_power_is_off(&pd->ch); ++ pr_debug("%s: %s is initialy %s\n", __func__, genpd->name, is_off ? "off" : "on"); ++ goto finalize; ++ } ++ + if (!rcar_sysc_power_is_off(&pd->ch)) { + pr_debug("%s: %s is already powered\n", __func__, genpd->name); + goto finalize; +@@ -286,7 +330,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) + rcar_sysc_power_up(&pd->ch); + + finalize: +- pm_genpd_init(genpd, gov, false); ++ pm_genpd_init(genpd, gov, is_off); + } + + static const struct of_device_id rcar_sysc_matches[] = { +@@ -442,6 +486,12 @@ static int __init rcar_sysc_pd_init(void) + pd->ch.isr_bit = area->isr_bit; + pd->flags = area->flags; + ++ if ((pd->flags & PD_WA_CLK) || ++ (area->parent >= 0 && (container_of(domains->domains[area->parent], ++ struct rcar_sysc_pd, genpd)->flags & PD_NO_INIT_ON)) ++ ) ++ pd->flags |= PD_NO_INIT_ON; ++ + rcar_sysc_pd_setup(pd); + if (area->parent >= 0) + pm_genpd_add_subdomain(domains->domains[area->parent], +@@ -479,6 +529,62 @@ static int __init rcar_sysc_pd_init2(void) + postcore_initcall(rcar_sysc_pd_init2); + #endif + ++#if IS_ENABLED(CONFIG_ARCH_R8A7797) || \ ++ IS_ENABLED(CONFIG_ARCH_R8A7798) ++static int __init rcar_sysc_pd_init3(void) ++{ ++ const struct rcar_sysc_info *info; ++ const struct of_device_id *match; ++ struct device_node *np; ++ unsigned int i, j; ++ ++ np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); ++ if (!np) ++ return -ENODEV; ++ ++ info = match->data; ++ ++ for (i = 0; i < info->num_areas; i++) { ++ const struct rcar_sysc_area *area = &info->areas[i]; ++ struct rcar_sysc_pd *pd = rcar_domains[i]; ++ ++ if (pd->flags & PD_WA_CLK) { ++ int err = 0; ++ ++ for (j = 0; j < RCAR_SYSC_MAX_WA_CLKS; j++) { ++ struct clk *wa_clk; ++ const char *wa_clk_name = area->wa_clk_names[j]; ++ ++ if (!wa_clk_name) ++ break; ++ ++ wa_clk = __clk_lookup(wa_clk_name); ++ if (!wa_clk) { ++ err = -ENODEV; ++ pr_err("%s: Unable to get clock %s for workaround\n", pd->name, wa_clk_name); ++ break; ++ } ++ ++ err = clk_prepare(wa_clk); ++ if (err) { ++ pr_err("%s: Unable to prepare clock %s for workaround\n", pd->name, wa_clk_name); ++ break; ++ } ++ ++ pd->wa_clk[j] = wa_clk; ++ } ++ ++ if (!err) ++ pd->flags |= PD_WA_CLK_RDY; ++ } ++ } ++ ++ return 0; ++} ++/* Should be called after cpg_mssr_driver is initialized */ ++subsys_initcall_sync(rcar_sysc_pd_init3); ++#endif ++ + void __init rcar_sysc_init(phys_addr_t base, u32 syscier) + { + u32 syscimr; +diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h +index dc58a58..b991103 100644 +--- a/drivers/soc/renesas/rcar-sysc.h ++++ b/drivers/soc/renesas/rcar-sysc.h +@@ -23,10 +23,15 @@ + #define PD_BUSY BIT(3) /* Busy, for internal use only */ + #define PD_ON_ONCE BIT(4) /* Turned on once at boot */ + ++#define PD_WA_CLK BIT(5) /* Use clocks for workaround */ ++#define PD_WA_CLK_RDY BIT(6) /* Clock ready, for internal use only */ ++#define PD_NO_INIT_ON BIT(7) /* Do not power on at initialization, for internal use */ ++ + #define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */ + #define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */ + #define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ + ++#define RCAR_SYSC_MAX_WA_CLKS 8 + + /* + * Description of a Power Area +@@ -39,6 +44,7 @@ struct rcar_sysc_area { + u8 isr_bit; /* Bit in SYSCI*R */ + int parent; /* -1 if none */ + unsigned int flags; /* See PD_* */ ++ const char* wa_clk_names[RCAR_SYSC_MAX_WA_CLKS]; /* Clocks needed by workaround for A3 PD issue */ + }; + + +-- +2.7.4 + -- cgit 1.2.3-korg