18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * ti-sysc.c - Texas Instruments sysc interconnect target driver 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/io.h> 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 98c2ecf20Sopenharmony_ci#include <linux/cpu_pm.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 158c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 168c2ecf20Sopenharmony_ci#include <linux/reset.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 198c2ecf20Sopenharmony_ci#include <linux/slab.h> 208c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 218c2ecf20Sopenharmony_ci#include <linux/timekeeping.h> 228c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/platform_data/ti-sysc.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <dt-bindings/bus/ti-sysc.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DIS_ISP BIT(2) 298c2ecf20Sopenharmony_ci#define DIS_IVA BIT(1) 308c2ecf20Sopenharmony_ci#define DIS_SGX BIT(0) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define MAX_MODULE_SOFTRESET_WAIT 10000 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cienum sysc_soc { 378c2ecf20Sopenharmony_ci SOC_UNKNOWN, 388c2ecf20Sopenharmony_ci SOC_2420, 398c2ecf20Sopenharmony_ci SOC_2430, 408c2ecf20Sopenharmony_ci SOC_3430, 418c2ecf20Sopenharmony_ci SOC_AM35, 428c2ecf20Sopenharmony_ci SOC_3630, 438c2ecf20Sopenharmony_ci SOC_4430, 448c2ecf20Sopenharmony_ci SOC_4460, 458c2ecf20Sopenharmony_ci SOC_4470, 468c2ecf20Sopenharmony_ci SOC_5430, 478c2ecf20Sopenharmony_ci SOC_AM3, 488c2ecf20Sopenharmony_ci SOC_AM4, 498c2ecf20Sopenharmony_ci SOC_DRA7, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistruct sysc_address { 538c2ecf20Sopenharmony_ci unsigned long base; 548c2ecf20Sopenharmony_ci struct list_head node; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct sysc_module { 588c2ecf20Sopenharmony_ci struct sysc *ddata; 598c2ecf20Sopenharmony_ci struct list_head node; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct sysc_soc_info { 638c2ecf20Sopenharmony_ci unsigned long general_purpose:1; 648c2ecf20Sopenharmony_ci enum sysc_soc soc; 658c2ecf20Sopenharmony_ci struct mutex list_lock; /* disabled and restored modules list lock */ 668c2ecf20Sopenharmony_ci struct list_head disabled_modules; 678c2ecf20Sopenharmony_ci struct list_head restored_modules; 688c2ecf20Sopenharmony_ci struct notifier_block nb; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cienum sysc_clocks { 728c2ecf20Sopenharmony_ci SYSC_FCK, 738c2ecf20Sopenharmony_ci SYSC_ICK, 748c2ecf20Sopenharmony_ci SYSC_OPTFCK0, 758c2ecf20Sopenharmony_ci SYSC_OPTFCK1, 768c2ecf20Sopenharmony_ci SYSC_OPTFCK2, 778c2ecf20Sopenharmony_ci SYSC_OPTFCK3, 788c2ecf20Sopenharmony_ci SYSC_OPTFCK4, 798c2ecf20Sopenharmony_ci SYSC_OPTFCK5, 808c2ecf20Sopenharmony_ci SYSC_OPTFCK6, 818c2ecf20Sopenharmony_ci SYSC_OPTFCK7, 828c2ecf20Sopenharmony_ci SYSC_MAX_CLOCKS, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic struct sysc_soc_info *sysc_soc; 868c2ecf20Sopenharmony_cistatic const char * const reg_names[] = { "rev", "sysc", "syss", }; 878c2ecf20Sopenharmony_cistatic const char * const clock_names[SYSC_MAX_CLOCKS] = { 888c2ecf20Sopenharmony_ci "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4", 898c2ecf20Sopenharmony_ci "opt5", "opt6", "opt7", 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define SYSC_IDLEMODE_MASK 3 938c2ecf20Sopenharmony_ci#define SYSC_CLOCKACTIVITY_MASK 3 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci/** 968c2ecf20Sopenharmony_ci * struct sysc - TI sysc interconnect target module registers and capabilities 978c2ecf20Sopenharmony_ci * @dev: struct device pointer 988c2ecf20Sopenharmony_ci * @module_pa: physical address of the interconnect target module 998c2ecf20Sopenharmony_ci * @module_size: size of the interconnect target module 1008c2ecf20Sopenharmony_ci * @module_va: virtual address of the interconnect target module 1018c2ecf20Sopenharmony_ci * @offsets: register offsets from module base 1028c2ecf20Sopenharmony_ci * @mdata: ti-sysc to hwmod translation data for a module 1038c2ecf20Sopenharmony_ci * @clocks: clocks used by the interconnect target module 1048c2ecf20Sopenharmony_ci * @clock_roles: clock role names for the found clocks 1058c2ecf20Sopenharmony_ci * @nr_clocks: number of clocks used by the interconnect target module 1068c2ecf20Sopenharmony_ci * @rsts: resets used by the interconnect target module 1078c2ecf20Sopenharmony_ci * @legacy_mode: configured for legacy mode if set 1088c2ecf20Sopenharmony_ci * @cap: interconnect target module capabilities 1098c2ecf20Sopenharmony_ci * @cfg: interconnect target module configuration 1108c2ecf20Sopenharmony_ci * @cookie: data used by legacy platform callbacks 1118c2ecf20Sopenharmony_ci * @name: name if available 1128c2ecf20Sopenharmony_ci * @revision: interconnect target module revision 1138c2ecf20Sopenharmony_ci * @reserved: target module is reserved and already in use 1148c2ecf20Sopenharmony_ci * @enabled: sysc runtime enabled status 1158c2ecf20Sopenharmony_ci * @needs_resume: runtime resume needed on resume from suspend 1168c2ecf20Sopenharmony_ci * @child_needs_resume: runtime resume needed for child on resume from suspend 1178c2ecf20Sopenharmony_ci * @disable_on_idle: status flag used for disabling modules with resets 1188c2ecf20Sopenharmony_ci * @idle_work: work structure used to perform delayed idle on a module 1198c2ecf20Sopenharmony_ci * @pre_reset_quirk: module specific pre-reset quirk 1208c2ecf20Sopenharmony_ci * @post_reset_quirk: module specific post-reset quirk 1218c2ecf20Sopenharmony_ci * @reset_done_quirk: module specific reset done quirk 1228c2ecf20Sopenharmony_ci * @module_enable_quirk: module specific enable quirk 1238c2ecf20Sopenharmony_ci * @module_disable_quirk: module specific disable quirk 1248c2ecf20Sopenharmony_ci * @module_unlock_quirk: module specific sysconfig unlock quirk 1258c2ecf20Sopenharmony_ci * @module_lock_quirk: module specific sysconfig lock quirk 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_cistruct sysc { 1288c2ecf20Sopenharmony_ci struct device *dev; 1298c2ecf20Sopenharmony_ci u64 module_pa; 1308c2ecf20Sopenharmony_ci u32 module_size; 1318c2ecf20Sopenharmony_ci void __iomem *module_va; 1328c2ecf20Sopenharmony_ci int offsets[SYSC_MAX_REGS]; 1338c2ecf20Sopenharmony_ci struct ti_sysc_module_data *mdata; 1348c2ecf20Sopenharmony_ci struct clk **clocks; 1358c2ecf20Sopenharmony_ci const char **clock_roles; 1368c2ecf20Sopenharmony_ci int nr_clocks; 1378c2ecf20Sopenharmony_ci struct reset_control *rsts; 1388c2ecf20Sopenharmony_ci const char *legacy_mode; 1398c2ecf20Sopenharmony_ci const struct sysc_capabilities *cap; 1408c2ecf20Sopenharmony_ci struct sysc_config cfg; 1418c2ecf20Sopenharmony_ci struct ti_sysc_cookie cookie; 1428c2ecf20Sopenharmony_ci const char *name; 1438c2ecf20Sopenharmony_ci u32 revision; 1448c2ecf20Sopenharmony_ci unsigned int reserved:1; 1458c2ecf20Sopenharmony_ci unsigned int enabled:1; 1468c2ecf20Sopenharmony_ci unsigned int needs_resume:1; 1478c2ecf20Sopenharmony_ci unsigned int child_needs_resume:1; 1488c2ecf20Sopenharmony_ci struct delayed_work idle_work; 1498c2ecf20Sopenharmony_ci void (*pre_reset_quirk)(struct sysc *sysc); 1508c2ecf20Sopenharmony_ci void (*post_reset_quirk)(struct sysc *sysc); 1518c2ecf20Sopenharmony_ci void (*reset_done_quirk)(struct sysc *sysc); 1528c2ecf20Sopenharmony_ci void (*module_enable_quirk)(struct sysc *sysc); 1538c2ecf20Sopenharmony_ci void (*module_disable_quirk)(struct sysc *sysc); 1548c2ecf20Sopenharmony_ci void (*module_unlock_quirk)(struct sysc *sysc); 1558c2ecf20Sopenharmony_ci void (*module_lock_quirk)(struct sysc *sysc); 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, 1598c2ecf20Sopenharmony_ci bool is_child); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void sysc_write(struct sysc *ddata, int offset, u32 value) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { 1648c2ecf20Sopenharmony_ci writew_relaxed(value & 0xffff, ddata->module_va + offset); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* Only i2c revision has LO and HI register with stride of 4 */ 1678c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_REVISION] >= 0 && 1688c2ecf20Sopenharmony_ci offset == ddata->offsets[SYSC_REVISION]) { 1698c2ecf20Sopenharmony_ci u16 hi = value >> 16; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci writew_relaxed(hi, ddata->module_va + offset + 4); 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci writel_relaxed(value, ddata->module_va + offset); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic u32 sysc_read(struct sysc *ddata, int offset) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { 1838c2ecf20Sopenharmony_ci u32 val; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci val = readw_relaxed(ddata->module_va + offset); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* Only i2c revision has LO and HI register with stride of 4 */ 1888c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_REVISION] >= 0 && 1898c2ecf20Sopenharmony_ci offset == ddata->offsets[SYSC_REVISION]) { 1908c2ecf20Sopenharmony_ci u16 tmp = readw_relaxed(ddata->module_va + offset + 4); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci val |= tmp << 16; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return val; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return readl_relaxed(ddata->module_va + offset); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic bool sysc_opt_clks_needed(struct sysc *ddata) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci return !!(ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_NEEDED); 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic u32 sysc_read_revision(struct sysc *ddata) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci int offset = ddata->offsets[SYSC_REVISION]; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (offset < 0) 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return sysc_read(ddata, offset); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic u32 sysc_read_sysconfig(struct sysc *ddata) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int offset = ddata->offsets[SYSC_SYSCONFIG]; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (offset < 0) 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return sysc_read(ddata, offset); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic u32 sysc_read_sysstatus(struct sysc *ddata) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci int offset = ddata->offsets[SYSC_SYSSTATUS]; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (offset < 0) 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return sysc_read(ddata, offset); 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int sysc_poll_reset_sysstatus(struct sysc *ddata) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci int error, retries; 2398c2ecf20Sopenharmony_ci u32 syss_done, rstval; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSS_QUIRK_RESETDONE_INVERTED) 2428c2ecf20Sopenharmony_ci syss_done = 0; 2438c2ecf20Sopenharmony_ci else 2448c2ecf20Sopenharmony_ci syss_done = ddata->cfg.syss_mask; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (likely(!timekeeping_suspended)) { 2478c2ecf20Sopenharmony_ci error = readx_poll_timeout_atomic(sysc_read_sysstatus, ddata, 2488c2ecf20Sopenharmony_ci rstval, (rstval & ddata->cfg.syss_mask) == 2498c2ecf20Sopenharmony_ci syss_done, 100, MAX_MODULE_SOFTRESET_WAIT); 2508c2ecf20Sopenharmony_ci } else { 2518c2ecf20Sopenharmony_ci retries = MAX_MODULE_SOFTRESET_WAIT; 2528c2ecf20Sopenharmony_ci while (retries--) { 2538c2ecf20Sopenharmony_ci rstval = sysc_read_sysstatus(ddata); 2548c2ecf20Sopenharmony_ci if ((rstval & ddata->cfg.syss_mask) == syss_done) 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci udelay(2); /* Account for udelay flakeyness */ 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci error = -ETIMEDOUT; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci return error; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic int sysc_poll_reset_sysconfig(struct sysc *ddata) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int error, retries; 2678c2ecf20Sopenharmony_ci u32 sysc_mask, rstval; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci sysc_mask = BIT(ddata->cap->regbits->srst_shift); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci if (likely(!timekeeping_suspended)) { 2728c2ecf20Sopenharmony_ci error = readx_poll_timeout_atomic(sysc_read_sysconfig, ddata, 2738c2ecf20Sopenharmony_ci rstval, !(rstval & sysc_mask), 2748c2ecf20Sopenharmony_ci 100, MAX_MODULE_SOFTRESET_WAIT); 2758c2ecf20Sopenharmony_ci } else { 2768c2ecf20Sopenharmony_ci retries = MAX_MODULE_SOFTRESET_WAIT; 2778c2ecf20Sopenharmony_ci while (retries--) { 2788c2ecf20Sopenharmony_ci rstval = sysc_read_sysconfig(ddata); 2798c2ecf20Sopenharmony_ci if (!(rstval & sysc_mask)) 2808c2ecf20Sopenharmony_ci return 0; 2818c2ecf20Sopenharmony_ci udelay(2); /* Account for udelay flakeyness */ 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci error = -ETIMEDOUT; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return error; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci/* Poll on reset status */ 2908c2ecf20Sopenharmony_cistatic int sysc_wait_softreset(struct sysc *ddata) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci int syss_offset, error = 0; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (ddata->cap->regbits->srst_shift < 0) 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci syss_offset = ddata->offsets[SYSC_SYSSTATUS]; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (syss_offset >= 0) 3008c2ecf20Sopenharmony_ci error = sysc_poll_reset_sysstatus(ddata); 3018c2ecf20Sopenharmony_ci else if (ddata->cfg.quirks & SYSC_QUIRK_RESET_STATUS) 3028c2ecf20Sopenharmony_ci error = sysc_poll_reset_sysconfig(ddata); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return error; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int sysc_add_named_clock_from_child(struct sysc *ddata, 3088c2ecf20Sopenharmony_ci const char *name, 3098c2ecf20Sopenharmony_ci const char *optfck_name) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 3128c2ecf20Sopenharmony_ci struct device_node *child; 3138c2ecf20Sopenharmony_ci struct clk_lookup *cl; 3148c2ecf20Sopenharmony_ci struct clk *clock; 3158c2ecf20Sopenharmony_ci const char *n; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (name) 3188c2ecf20Sopenharmony_ci n = name; 3198c2ecf20Sopenharmony_ci else 3208c2ecf20Sopenharmony_ci n = optfck_name; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* Does the clock alias already exist? */ 3238c2ecf20Sopenharmony_ci clock = of_clk_get_by_name(np, n); 3248c2ecf20Sopenharmony_ci if (!IS_ERR(clock)) { 3258c2ecf20Sopenharmony_ci clk_put(clock); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci child = of_get_next_available_child(np, NULL); 3318c2ecf20Sopenharmony_ci if (!child) 3328c2ecf20Sopenharmony_ci return -ENODEV; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci clock = devm_get_clk_from_child(ddata->dev, child, name); 3358c2ecf20Sopenharmony_ci if (IS_ERR(clock)) 3368c2ecf20Sopenharmony_ci return PTR_ERR(clock); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * Use clkdev_add() instead of clkdev_alloc() to avoid the MAX_DEV_ID 3408c2ecf20Sopenharmony_ci * limit for clk_get(). If cl ever needs to be freed, it should be done 3418c2ecf20Sopenharmony_ci * with clkdev_drop(). 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci cl = kcalloc(1, sizeof(*cl), GFP_KERNEL); 3448c2ecf20Sopenharmony_ci if (!cl) 3458c2ecf20Sopenharmony_ci return -ENOMEM; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci cl->con_id = n; 3488c2ecf20Sopenharmony_ci cl->dev_id = dev_name(ddata->dev); 3498c2ecf20Sopenharmony_ci cl->clk = clock; 3508c2ecf20Sopenharmony_ci clkdev_add(cl); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci clk_put(clock); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int sysc_init_ext_opt_clock(struct sysc *ddata, const char *name) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci const char *optfck_name; 3608c2ecf20Sopenharmony_ci int error, index; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (ddata->nr_clocks < SYSC_OPTFCK0) 3638c2ecf20Sopenharmony_ci index = SYSC_OPTFCK0; 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci index = ddata->nr_clocks; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (name) 3688c2ecf20Sopenharmony_ci optfck_name = name; 3698c2ecf20Sopenharmony_ci else 3708c2ecf20Sopenharmony_ci optfck_name = clock_names[index]; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci error = sysc_add_named_clock_from_child(ddata, name, optfck_name); 3738c2ecf20Sopenharmony_ci if (error) 3748c2ecf20Sopenharmony_ci return error; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci ddata->clock_roles[index] = optfck_name; 3778c2ecf20Sopenharmony_ci ddata->nr_clocks++; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci return 0; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic int sysc_get_one_clock(struct sysc *ddata, const char *name) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci int error, i, index = -ENODEV; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (!strncmp(clock_names[SYSC_FCK], name, 3)) 3878c2ecf20Sopenharmony_ci index = SYSC_FCK; 3888c2ecf20Sopenharmony_ci else if (!strncmp(clock_names[SYSC_ICK], name, 3)) 3898c2ecf20Sopenharmony_ci index = SYSC_ICK; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (index < 0) { 3928c2ecf20Sopenharmony_ci for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) { 3938c2ecf20Sopenharmony_ci if (!ddata->clocks[i]) { 3948c2ecf20Sopenharmony_ci index = i; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (index < 0) { 4018c2ecf20Sopenharmony_ci dev_err(ddata->dev, "clock %s not added\n", name); 4028c2ecf20Sopenharmony_ci return index; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci ddata->clocks[index] = devm_clk_get(ddata->dev, name); 4068c2ecf20Sopenharmony_ci if (IS_ERR(ddata->clocks[index])) { 4078c2ecf20Sopenharmony_ci dev_err(ddata->dev, "clock get error for %s: %li\n", 4088c2ecf20Sopenharmony_ci name, PTR_ERR(ddata->clocks[index])); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return PTR_ERR(ddata->clocks[index]); 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci error = clk_prepare(ddata->clocks[index]); 4148c2ecf20Sopenharmony_ci if (error) { 4158c2ecf20Sopenharmony_ci dev_err(ddata->dev, "clock prepare error for %s: %i\n", 4168c2ecf20Sopenharmony_ci name, error); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return error; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci return 0; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic int sysc_get_clocks(struct sysc *ddata) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 4278c2ecf20Sopenharmony_ci struct property *prop; 4288c2ecf20Sopenharmony_ci const char *name; 4298c2ecf20Sopenharmony_ci int nr_fck = 0, nr_ick = 0, i, error = 0; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ddata->clock_roles = devm_kcalloc(ddata->dev, 4328c2ecf20Sopenharmony_ci SYSC_MAX_CLOCKS, 4338c2ecf20Sopenharmony_ci sizeof(*ddata->clock_roles), 4348c2ecf20Sopenharmony_ci GFP_KERNEL); 4358c2ecf20Sopenharmony_ci if (!ddata->clock_roles) 4368c2ecf20Sopenharmony_ci return -ENOMEM; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci of_property_for_each_string(np, "clock-names", prop, name) { 4398c2ecf20Sopenharmony_ci if (!strncmp(clock_names[SYSC_FCK], name, 3)) 4408c2ecf20Sopenharmony_ci nr_fck++; 4418c2ecf20Sopenharmony_ci if (!strncmp(clock_names[SYSC_ICK], name, 3)) 4428c2ecf20Sopenharmony_ci nr_ick++; 4438c2ecf20Sopenharmony_ci ddata->clock_roles[ddata->nr_clocks] = name; 4448c2ecf20Sopenharmony_ci ddata->nr_clocks++; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (ddata->nr_clocks < 1) 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if ((ddata->cfg.quirks & SYSC_QUIRK_EXT_OPT_CLOCK)) { 4518c2ecf20Sopenharmony_ci error = sysc_init_ext_opt_clock(ddata, NULL); 4528c2ecf20Sopenharmony_ci if (error) 4538c2ecf20Sopenharmony_ci return error; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (ddata->nr_clocks > SYSC_MAX_CLOCKS) { 4578c2ecf20Sopenharmony_ci dev_err(ddata->dev, "too many clocks for %pOF\n", np); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci return -EINVAL; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (nr_fck > 1 || nr_ick > 1) { 4638c2ecf20Sopenharmony_ci dev_err(ddata->dev, "max one fck and ick for %pOF\n", np); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return -EINVAL; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Always add a slot for main clocks fck and ick even if unused */ 4698c2ecf20Sopenharmony_ci if (!nr_fck) 4708c2ecf20Sopenharmony_ci ddata->nr_clocks++; 4718c2ecf20Sopenharmony_ci if (!nr_ick) 4728c2ecf20Sopenharmony_ci ddata->nr_clocks++; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci ddata->clocks = devm_kcalloc(ddata->dev, 4758c2ecf20Sopenharmony_ci ddata->nr_clocks, sizeof(*ddata->clocks), 4768c2ecf20Sopenharmony_ci GFP_KERNEL); 4778c2ecf20Sopenharmony_ci if (!ddata->clocks) 4788c2ecf20Sopenharmony_ci return -ENOMEM; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_MAX_CLOCKS; i++) { 4818c2ecf20Sopenharmony_ci const char *name = ddata->clock_roles[i]; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!name) 4848c2ecf20Sopenharmony_ci continue; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci error = sysc_get_one_clock(ddata, name); 4878c2ecf20Sopenharmony_ci if (error) 4888c2ecf20Sopenharmony_ci return error; 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int sysc_enable_main_clocks(struct sysc *ddata) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct clk *clock; 4978c2ecf20Sopenharmony_ci int i, error; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (!ddata->clocks) 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_OPTFCK0; i++) { 5038c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* Main clocks may not have ick */ 5068c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5078c2ecf20Sopenharmony_ci continue; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci error = clk_enable(clock); 5108c2ecf20Sopenharmony_ci if (error) 5118c2ecf20Sopenharmony_ci goto err_disable; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci return 0; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cierr_disable: 5178c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 5188c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci /* Main clocks may not have ick */ 5218c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5228c2ecf20Sopenharmony_ci continue; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci clk_disable(clock); 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci return error; 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void sysc_disable_main_clocks(struct sysc *ddata) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct clk *clock; 5338c2ecf20Sopenharmony_ci int i; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci if (!ddata->clocks) 5368c2ecf20Sopenharmony_ci return; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_OPTFCK0; i++) { 5398c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5408c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5418c2ecf20Sopenharmony_ci continue; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci clk_disable(clock); 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic int sysc_enable_opt_clocks(struct sysc *ddata) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci struct clk *clock; 5508c2ecf20Sopenharmony_ci int i, error; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (!ddata->clocks || ddata->nr_clocks < SYSC_OPTFCK0 + 1) 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) { 5568c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci /* Assume no holes for opt clocks */ 5598c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5608c2ecf20Sopenharmony_ci return 0; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci error = clk_enable(clock); 5638c2ecf20Sopenharmony_ci if (error) 5648c2ecf20Sopenharmony_ci goto err_disable; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cierr_disable: 5708c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) { 5718c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5728c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5738c2ecf20Sopenharmony_ci continue; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci clk_disable(clock); 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci return error; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_cistatic void sysc_disable_opt_clocks(struct sysc *ddata) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci struct clk *clock; 5848c2ecf20Sopenharmony_ci int i; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (!ddata->clocks || ddata->nr_clocks < SYSC_OPTFCK0 + 1) 5878c2ecf20Sopenharmony_ci return; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci for (i = SYSC_OPTFCK0; i < SYSC_MAX_CLOCKS; i++) { 5908c2ecf20Sopenharmony_ci clock = ddata->clocks[i]; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Assume no holes for opt clocks */ 5938c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clock)) 5948c2ecf20Sopenharmony_ci return; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci clk_disable(clock); 5978c2ecf20Sopenharmony_ci } 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic void sysc_clkdm_deny_idle(struct sysc *ddata) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO)) 6058c2ecf20Sopenharmony_ci return; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci pdata = dev_get_platdata(ddata->dev); 6088c2ecf20Sopenharmony_ci if (pdata && pdata->clkdm_deny_idle) 6098c2ecf20Sopenharmony_ci pdata->clkdm_deny_idle(ddata->dev, &ddata->cookie); 6108c2ecf20Sopenharmony_ci} 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_cistatic void sysc_clkdm_allow_idle(struct sysc *ddata) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (ddata->legacy_mode || (ddata->cfg.quirks & SYSC_QUIRK_CLKDM_NOAUTO)) 6178c2ecf20Sopenharmony_ci return; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci pdata = dev_get_platdata(ddata->dev); 6208c2ecf20Sopenharmony_ci if (pdata && pdata->clkdm_allow_idle) 6218c2ecf20Sopenharmony_ci pdata->clkdm_allow_idle(ddata->dev, &ddata->cookie); 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci/** 6258c2ecf20Sopenharmony_ci * sysc_init_resets - init rstctrl reset line if configured 6268c2ecf20Sopenharmony_ci * @ddata: device driver data 6278c2ecf20Sopenharmony_ci * 6288c2ecf20Sopenharmony_ci * See sysc_rstctrl_reset_deassert(). 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_cistatic int sysc_init_resets(struct sysc *ddata) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci ddata->rsts = 6338c2ecf20Sopenharmony_ci devm_reset_control_get_optional_shared(ddata->dev, "rstctrl"); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(ddata->rsts); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci/** 6398c2ecf20Sopenharmony_ci * sysc_parse_and_check_child_range - parses module IO region from ranges 6408c2ecf20Sopenharmony_ci * @ddata: device driver data 6418c2ecf20Sopenharmony_ci * 6428c2ecf20Sopenharmony_ci * In general we only need rev, syss, and sysc registers and not the whole 6438c2ecf20Sopenharmony_ci * module range. But we do want the offsets for these registers from the 6448c2ecf20Sopenharmony_ci * module base. This allows us to check them against the legacy hwmod 6458c2ecf20Sopenharmony_ci * platform data. Let's also check the ranges are configured properly. 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_cistatic int sysc_parse_and_check_child_range(struct sysc *ddata) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 6508c2ecf20Sopenharmony_ci const __be32 *ranges; 6518c2ecf20Sopenharmony_ci u32 nr_addr, nr_size; 6528c2ecf20Sopenharmony_ci int len, error; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci ranges = of_get_property(np, "ranges", &len); 6558c2ecf20Sopenharmony_ci if (!ranges) { 6568c2ecf20Sopenharmony_ci dev_err(ddata->dev, "missing ranges for %pOF\n", np); 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci return -ENOENT; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci len /= sizeof(*ranges); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (len < 3) { 6648c2ecf20Sopenharmony_ci dev_err(ddata->dev, "incomplete ranges for %pOF\n", np); 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci return -EINVAL; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci error = of_property_read_u32(np, "#address-cells", &nr_addr); 6708c2ecf20Sopenharmony_ci if (error) 6718c2ecf20Sopenharmony_ci return -ENOENT; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci error = of_property_read_u32(np, "#size-cells", &nr_size); 6748c2ecf20Sopenharmony_ci if (error) 6758c2ecf20Sopenharmony_ci return -ENOENT; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (nr_addr != 1 || nr_size != 1) { 6788c2ecf20Sopenharmony_ci dev_err(ddata->dev, "invalid ranges for %pOF\n", np); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci return -EINVAL; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci ranges++; 6848c2ecf20Sopenharmony_ci ddata->module_pa = of_translate_address(np, ranges++); 6858c2ecf20Sopenharmony_ci ddata->module_size = be32_to_cpup(ranges); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return 0; 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci/* Interconnect instances to probe before l4_per instances */ 6918c2ecf20Sopenharmony_cistatic struct resource early_bus_ranges[] = { 6928c2ecf20Sopenharmony_ci /* am3/4 l4_wkup */ 6938c2ecf20Sopenharmony_ci { .start = 0x44c00000, .end = 0x44c00000 + 0x300000, }, 6948c2ecf20Sopenharmony_ci /* omap4/5 and dra7 l4_cfg */ 6958c2ecf20Sopenharmony_ci { .start = 0x4a000000, .end = 0x4a000000 + 0x300000, }, 6968c2ecf20Sopenharmony_ci /* omap4 l4_wkup */ 6978c2ecf20Sopenharmony_ci { .start = 0x4a300000, .end = 0x4a300000 + 0x30000, }, 6988c2ecf20Sopenharmony_ci /* omap5 and dra7 l4_wkup without dra7 dcan segment */ 6998c2ecf20Sopenharmony_ci { .start = 0x4ae00000, .end = 0x4ae00000 + 0x30000, }, 7008c2ecf20Sopenharmony_ci}; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic atomic_t sysc_defer = ATOMIC_INIT(10); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci/** 7058c2ecf20Sopenharmony_ci * sysc_defer_non_critical - defer non_critical interconnect probing 7068c2ecf20Sopenharmony_ci * @ddata: device driver data 7078c2ecf20Sopenharmony_ci * 7088c2ecf20Sopenharmony_ci * We want to probe l4_cfg and l4_wkup interconnect instances before any 7098c2ecf20Sopenharmony_ci * l4_per instances as l4_per instances depend on resources on l4_cfg and 7108c2ecf20Sopenharmony_ci * l4_wkup interconnects. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_cistatic int sysc_defer_non_critical(struct sysc *ddata) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct resource *res; 7158c2ecf20Sopenharmony_ci int i; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (!atomic_read(&sysc_defer)) 7188c2ecf20Sopenharmony_ci return 0; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(early_bus_ranges); i++) { 7218c2ecf20Sopenharmony_ci res = &early_bus_ranges[i]; 7228c2ecf20Sopenharmony_ci if (ddata->module_pa >= res->start && 7238c2ecf20Sopenharmony_ci ddata->module_pa <= res->end) { 7248c2ecf20Sopenharmony_ci atomic_set(&sysc_defer, 0); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci atomic_dec_if_positive(&sysc_defer); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic struct device_node *stdout_path; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic void sysc_init_stdout_path(struct sysc *ddata) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci struct device_node *np = NULL; 7408c2ecf20Sopenharmony_ci const char *uart; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (IS_ERR(stdout_path)) 7438c2ecf20Sopenharmony_ci return; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if (stdout_path) 7468c2ecf20Sopenharmony_ci return; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci np = of_find_node_by_path("/chosen"); 7498c2ecf20Sopenharmony_ci if (!np) 7508c2ecf20Sopenharmony_ci goto err; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci uart = of_get_property(np, "stdout-path", NULL); 7538c2ecf20Sopenharmony_ci if (!uart) 7548c2ecf20Sopenharmony_ci goto err; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci np = of_find_node_by_path(uart); 7578c2ecf20Sopenharmony_ci if (!np) 7588c2ecf20Sopenharmony_ci goto err; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci stdout_path = np; 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cierr: 7658c2ecf20Sopenharmony_ci stdout_path = ERR_PTR(-ENODEV); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_cistatic void sysc_check_quirk_stdout(struct sysc *ddata, 7698c2ecf20Sopenharmony_ci struct device_node *np) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci sysc_init_stdout_path(ddata); 7728c2ecf20Sopenharmony_ci if (np != stdout_path) 7738c2ecf20Sopenharmony_ci return; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci ddata->cfg.quirks |= SYSC_QUIRK_NO_IDLE_ON_INIT | 7768c2ecf20Sopenharmony_ci SYSC_QUIRK_NO_RESET_ON_INIT; 7778c2ecf20Sopenharmony_ci} 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci/** 7808c2ecf20Sopenharmony_ci * sysc_check_one_child - check child configuration 7818c2ecf20Sopenharmony_ci * @ddata: device driver data 7828c2ecf20Sopenharmony_ci * @np: child device node 7838c2ecf20Sopenharmony_ci * 7848c2ecf20Sopenharmony_ci * Let's avoid messy situations where we have new interconnect target 7858c2ecf20Sopenharmony_ci * node but children have "ti,hwmods". These belong to the interconnect 7868c2ecf20Sopenharmony_ci * target node and are managed by this driver. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_cistatic void sysc_check_one_child(struct sysc *ddata, 7898c2ecf20Sopenharmony_ci struct device_node *np) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci const char *name; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci name = of_get_property(np, "ti,hwmods", NULL); 7948c2ecf20Sopenharmony_ci if (name && !of_device_is_compatible(np, "ti,sysc")) 7958c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "really a child ti,hwmods property?"); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci sysc_check_quirk_stdout(ddata, np); 7988c2ecf20Sopenharmony_ci sysc_parse_dts_quirks(ddata, np, true); 7998c2ecf20Sopenharmony_ci} 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_cistatic void sysc_check_children(struct sysc *ddata) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct device_node *child; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci for_each_child_of_node(ddata->dev->of_node, child) 8068c2ecf20Sopenharmony_ci sysc_check_one_child(ddata, child); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci/* 8108c2ecf20Sopenharmony_ci * So far only I2C uses 16-bit read access with clockactivity with revision 8118c2ecf20Sopenharmony_ci * in two registers with stride of 4. We can detect this based on the rev 8128c2ecf20Sopenharmony_ci * register size to configure things far enough to be able to properly read 8138c2ecf20Sopenharmony_ci * the revision register. 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_cistatic void sysc_check_quirk_16bit(struct sysc *ddata, struct resource *res) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci if (resource_size(res) == 8) 8188c2ecf20Sopenharmony_ci ddata->cfg.quirks |= SYSC_QUIRK_16BIT | SYSC_QUIRK_USE_CLOCKACT; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci/** 8228c2ecf20Sopenharmony_ci * sysc_parse_one - parses the interconnect target module registers 8238c2ecf20Sopenharmony_ci * @ddata: device driver data 8248c2ecf20Sopenharmony_ci * @reg: register to parse 8258c2ecf20Sopenharmony_ci */ 8268c2ecf20Sopenharmony_cistatic int sysc_parse_one(struct sysc *ddata, enum sysc_registers reg) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct resource *res; 8298c2ecf20Sopenharmony_ci const char *name; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci switch (reg) { 8328c2ecf20Sopenharmony_ci case SYSC_REVISION: 8338c2ecf20Sopenharmony_ci case SYSC_SYSCONFIG: 8348c2ecf20Sopenharmony_ci case SYSC_SYSSTATUS: 8358c2ecf20Sopenharmony_ci name = reg_names[reg]; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci default: 8388c2ecf20Sopenharmony_ci return -EINVAL; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci res = platform_get_resource_byname(to_platform_device(ddata->dev), 8428c2ecf20Sopenharmony_ci IORESOURCE_MEM, name); 8438c2ecf20Sopenharmony_ci if (!res) { 8448c2ecf20Sopenharmony_ci ddata->offsets[reg] = -ENODEV; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci return 0; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ddata->offsets[reg] = res->start - ddata->module_pa; 8508c2ecf20Sopenharmony_ci if (reg == SYSC_REVISION) 8518c2ecf20Sopenharmony_ci sysc_check_quirk_16bit(ddata, res); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return 0; 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int sysc_parse_registers(struct sysc *ddata) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci int i, error; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_MAX_REGS; i++) { 8618c2ecf20Sopenharmony_ci error = sysc_parse_one(ddata, i); 8628c2ecf20Sopenharmony_ci if (error) 8638c2ecf20Sopenharmony_ci return error; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci/** 8708c2ecf20Sopenharmony_ci * sysc_check_registers - check for misconfigured register overlaps 8718c2ecf20Sopenharmony_ci * @ddata: device driver data 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_cistatic int sysc_check_registers(struct sysc *ddata) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci int i, j, nr_regs = 0, nr_matches = 0; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_MAX_REGS; i++) { 8788c2ecf20Sopenharmony_ci if (ddata->offsets[i] < 0) 8798c2ecf20Sopenharmony_ci continue; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (ddata->offsets[i] > (ddata->module_size - 4)) { 8828c2ecf20Sopenharmony_ci dev_err(ddata->dev, "register outside module range"); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci return -EINVAL; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci for (j = 0; j < SYSC_MAX_REGS; j++) { 8888c2ecf20Sopenharmony_ci if (ddata->offsets[j] < 0) 8898c2ecf20Sopenharmony_ci continue; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (ddata->offsets[i] == ddata->offsets[j]) 8928c2ecf20Sopenharmony_ci nr_matches++; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci nr_regs++; 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci if (nr_matches > nr_regs) { 8988c2ecf20Sopenharmony_ci dev_err(ddata->dev, "overlapping registers: (%i/%i)", 8998c2ecf20Sopenharmony_ci nr_regs, nr_matches); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return -EINVAL; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci/** 9088c2ecf20Sopenharmony_ci * syc_ioremap - ioremap register space for the interconnect target module 9098c2ecf20Sopenharmony_ci * @ddata: device driver data 9108c2ecf20Sopenharmony_ci * 9118c2ecf20Sopenharmony_ci * Note that the interconnect target module registers can be anywhere 9128c2ecf20Sopenharmony_ci * within the interconnect target module range. For example, SGX has 9138c2ecf20Sopenharmony_ci * them at offset 0x1fc00 in the 32MB module address space. And cpsw 9148c2ecf20Sopenharmony_ci * has them at offset 0x1200 in the CPSW_WR child. Usually the 9158c2ecf20Sopenharmony_ci * the interconnect target module registers are at the beginning of 9168c2ecf20Sopenharmony_ci * the module range though. 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_cistatic int sysc_ioremap(struct sysc *ddata) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci int size; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_REVISION] < 0 && 9238c2ecf20Sopenharmony_ci ddata->offsets[SYSC_SYSCONFIG] < 0 && 9248c2ecf20Sopenharmony_ci ddata->offsets[SYSC_SYSSTATUS] < 0) { 9258c2ecf20Sopenharmony_ci size = ddata->module_size; 9268c2ecf20Sopenharmony_ci } else { 9278c2ecf20Sopenharmony_ci size = max3(ddata->offsets[SYSC_REVISION], 9288c2ecf20Sopenharmony_ci ddata->offsets[SYSC_SYSCONFIG], 9298c2ecf20Sopenharmony_ci ddata->offsets[SYSC_SYSSTATUS]); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (size < SZ_1K) 9328c2ecf20Sopenharmony_ci size = SZ_1K; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci if ((size + sizeof(u32)) > ddata->module_size) 9358c2ecf20Sopenharmony_ci size = ddata->module_size; 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci ddata->module_va = devm_ioremap(ddata->dev, 9398c2ecf20Sopenharmony_ci ddata->module_pa, 9408c2ecf20Sopenharmony_ci size + sizeof(u32)); 9418c2ecf20Sopenharmony_ci if (!ddata->module_va) 9428c2ecf20Sopenharmony_ci return -EIO; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci/** 9488c2ecf20Sopenharmony_ci * sysc_map_and_check_registers - ioremap and check device registers 9498c2ecf20Sopenharmony_ci * @ddata: device driver data 9508c2ecf20Sopenharmony_ci */ 9518c2ecf20Sopenharmony_cistatic int sysc_map_and_check_registers(struct sysc *ddata) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci int error; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci error = sysc_parse_and_check_child_range(ddata); 9568c2ecf20Sopenharmony_ci if (error) 9578c2ecf20Sopenharmony_ci return error; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci error = sysc_defer_non_critical(ddata); 9608c2ecf20Sopenharmony_ci if (error) 9618c2ecf20Sopenharmony_ci return error; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci sysc_check_children(ddata); 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci error = sysc_parse_registers(ddata); 9668c2ecf20Sopenharmony_ci if (error) 9678c2ecf20Sopenharmony_ci return error; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci error = sysc_ioremap(ddata); 9708c2ecf20Sopenharmony_ci if (error) 9718c2ecf20Sopenharmony_ci return error; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci error = sysc_check_registers(ddata); 9748c2ecf20Sopenharmony_ci if (error) 9758c2ecf20Sopenharmony_ci return error; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci/** 9818c2ecf20Sopenharmony_ci * sysc_show_rev - read and show interconnect target module revision 9828c2ecf20Sopenharmony_ci * @bufp: buffer to print the information to 9838c2ecf20Sopenharmony_ci * @ddata: device driver data 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_cistatic int sysc_show_rev(char *bufp, struct sysc *ddata) 9868c2ecf20Sopenharmony_ci{ 9878c2ecf20Sopenharmony_ci int len; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_REVISION] < 0) 9908c2ecf20Sopenharmony_ci return sprintf(bufp, ":NA"); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci len = sprintf(bufp, ":%08x", ddata->revision); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci return len; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic int sysc_show_reg(struct sysc *ddata, 9988c2ecf20Sopenharmony_ci char *bufp, enum sysc_registers reg) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci if (ddata->offsets[reg] < 0) 10018c2ecf20Sopenharmony_ci return sprintf(bufp, ":NA"); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci return sprintf(bufp, ":%x", ddata->offsets[reg]); 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_cistatic int sysc_show_name(char *bufp, struct sysc *ddata) 10078c2ecf20Sopenharmony_ci{ 10088c2ecf20Sopenharmony_ci if (!ddata->name) 10098c2ecf20Sopenharmony_ci return 0; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return sprintf(bufp, ":%s", ddata->name); 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci/** 10158c2ecf20Sopenharmony_ci * sysc_show_registers - show information about interconnect target module 10168c2ecf20Sopenharmony_ci * @ddata: device driver data 10178c2ecf20Sopenharmony_ci */ 10188c2ecf20Sopenharmony_cistatic void sysc_show_registers(struct sysc *ddata) 10198c2ecf20Sopenharmony_ci{ 10208c2ecf20Sopenharmony_ci char buf[128]; 10218c2ecf20Sopenharmony_ci char *bufp = buf; 10228c2ecf20Sopenharmony_ci int i; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_MAX_REGS; i++) 10258c2ecf20Sopenharmony_ci bufp += sysc_show_reg(ddata, bufp, i); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci bufp += sysc_show_rev(bufp, ddata); 10288c2ecf20Sopenharmony_ci bufp += sysc_show_name(bufp, ddata); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci dev_dbg(ddata->dev, "%llx:%x%s\n", 10318c2ecf20Sopenharmony_ci ddata->module_pa, ddata->module_size, 10328c2ecf20Sopenharmony_ci buf); 10338c2ecf20Sopenharmony_ci} 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci/** 10368c2ecf20Sopenharmony_ci * sysc_write_sysconfig - handle sysconfig quirks for register write 10378c2ecf20Sopenharmony_ci * @ddata: device driver data 10388c2ecf20Sopenharmony_ci * @value: register value 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_cistatic void sysc_write_sysconfig(struct sysc *ddata, u32 value) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci if (ddata->module_unlock_quirk) 10438c2ecf20Sopenharmony_ci ddata->module_unlock_quirk(ddata); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], value); 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (ddata->module_lock_quirk) 10488c2ecf20Sopenharmony_ci ddata->module_lock_quirk(ddata); 10498c2ecf20Sopenharmony_ci} 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci#define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1) 10528c2ecf20Sopenharmony_ci#define SYSC_CLOCACT_ICK 2 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */ 10558c2ecf20Sopenharmony_cistatic int sysc_enable_module(struct device *dev) 10568c2ecf20Sopenharmony_ci{ 10578c2ecf20Sopenharmony_ci struct sysc *ddata; 10588c2ecf20Sopenharmony_ci const struct sysc_regbits *regbits; 10598c2ecf20Sopenharmony_ci u32 reg, idlemodes, best_mode; 10608c2ecf20Sopenharmony_ci int error; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* 10658c2ecf20Sopenharmony_ci * Some modules like DSS reset automatically on idle. Enable optional 10668c2ecf20Sopenharmony_ci * reset clocks and wait for OCP softreset to complete. 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) { 10698c2ecf20Sopenharmony_ci error = sysc_enable_opt_clocks(ddata); 10708c2ecf20Sopenharmony_ci if (error) { 10718c2ecf20Sopenharmony_ci dev_err(ddata->dev, 10728c2ecf20Sopenharmony_ci "Optional clocks failed for enable: %i\n", 10738c2ecf20Sopenharmony_ci error); 10748c2ecf20Sopenharmony_ci return error; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci /* 10788c2ecf20Sopenharmony_ci * Some modules like i2c and hdq1w have unusable reset status unless 10798c2ecf20Sopenharmony_ci * the module reset quirk is enabled. Skip status check on enable. 10808c2ecf20Sopenharmony_ci */ 10818c2ecf20Sopenharmony_ci if (!(ddata->cfg.quirks & SYSC_MODULE_QUIRK_ENA_RESETDONE)) { 10828c2ecf20Sopenharmony_ci error = sysc_wait_softreset(ddata); 10838c2ecf20Sopenharmony_ci if (error) 10848c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "OCP softreset timed out\n"); 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_OPT_CLKS_IN_RESET) 10878c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* 10908c2ecf20Sopenharmony_ci * Some subsystem private interconnects, like DSS top level module, 10918c2ecf20Sopenharmony_ci * need only the automatic OCP softreset handling with no sysconfig 10928c2ecf20Sopenharmony_ci * register bits to configure. 10938c2ecf20Sopenharmony_ci */ 10948c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV) 10958c2ecf20Sopenharmony_ci return 0; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci regbits = ddata->cap->regbits; 10988c2ecf20Sopenharmony_ci reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci /* 11018c2ecf20Sopenharmony_ci * Set CLOCKACTIVITY, we only use it for ick. And we only configure it 11028c2ecf20Sopenharmony_ci * based on the SYSC_QUIRK_USE_CLOCKACT flag, not based on the hardware 11038c2ecf20Sopenharmony_ci * capabilities. See the old HWMOD_SET_DEFAULT_CLOCKACT flag. 11048c2ecf20Sopenharmony_ci */ 11058c2ecf20Sopenharmony_ci if (regbits->clkact_shift >= 0 && 11068c2ecf20Sopenharmony_ci (ddata->cfg.quirks & SYSC_QUIRK_USE_CLOCKACT)) 11078c2ecf20Sopenharmony_ci reg |= SYSC_CLOCACT_ICK << regbits->clkact_shift; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci /* Set SIDLE mode */ 11108c2ecf20Sopenharmony_ci idlemodes = ddata->cfg.sidlemodes; 11118c2ecf20Sopenharmony_ci if (!idlemodes || regbits->sidle_shift < 0) 11128c2ecf20Sopenharmony_ci goto set_midle; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE | 11158c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT)) { 11168c2ecf20Sopenharmony_ci best_mode = SYSC_IDLE_NO; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* Clear WAKEUP */ 11198c2ecf20Sopenharmony_ci if (regbits->enwkup_shift >= 0 && 11208c2ecf20Sopenharmony_ci ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) 11218c2ecf20Sopenharmony_ci reg &= ~BIT(regbits->enwkup_shift); 11228c2ecf20Sopenharmony_ci } else { 11238c2ecf20Sopenharmony_ci best_mode = fls(ddata->cfg.sidlemodes) - 1; 11248c2ecf20Sopenharmony_ci if (best_mode > SYSC_IDLE_MASK) { 11258c2ecf20Sopenharmony_ci dev_err(dev, "%s: invalid sidlemode\n", __func__); 11268c2ecf20Sopenharmony_ci return -EINVAL; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci /* Set WAKEUP */ 11308c2ecf20Sopenharmony_ci if (regbits->enwkup_shift >= 0 && 11318c2ecf20Sopenharmony_ci ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) 11328c2ecf20Sopenharmony_ci reg |= BIT(regbits->enwkup_shift); 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); 11368c2ecf20Sopenharmony_ci reg |= best_mode << regbits->sidle_shift; 11378c2ecf20Sopenharmony_ci sysc_write_sysconfig(ddata, reg); 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ciset_midle: 11408c2ecf20Sopenharmony_ci /* Set MIDLE mode */ 11418c2ecf20Sopenharmony_ci idlemodes = ddata->cfg.midlemodes; 11428c2ecf20Sopenharmony_ci if (!idlemodes || regbits->midle_shift < 0) 11438c2ecf20Sopenharmony_ci goto set_autoidle; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci best_mode = fls(ddata->cfg.midlemodes) - 1; 11468c2ecf20Sopenharmony_ci if (best_mode > SYSC_IDLE_MASK) { 11478c2ecf20Sopenharmony_ci dev_err(dev, "%s: invalid midlemode\n", __func__); 11488c2ecf20Sopenharmony_ci return -EINVAL; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_MSTANDBY) 11528c2ecf20Sopenharmony_ci best_mode = SYSC_IDLE_NO; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); 11558c2ecf20Sopenharmony_ci reg |= best_mode << regbits->midle_shift; 11568c2ecf20Sopenharmony_ci sysc_write_sysconfig(ddata, reg); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ciset_autoidle: 11598c2ecf20Sopenharmony_ci /* Autoidle bit must enabled separately if available */ 11608c2ecf20Sopenharmony_ci if (regbits->autoidle_shift >= 0 && 11618c2ecf20Sopenharmony_ci ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) { 11628c2ecf20Sopenharmony_ci reg |= 1 << regbits->autoidle_shift; 11638c2ecf20Sopenharmony_ci sysc_write_sysconfig(ddata, reg); 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci /* Flush posted write */ 11678c2ecf20Sopenharmony_ci sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (ddata->module_enable_quirk) 11708c2ecf20Sopenharmony_ci ddata->module_enable_quirk(ddata); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci return 0; 11738c2ecf20Sopenharmony_ci} 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_cistatic int sysc_best_idle_mode(u32 idlemodes, u32 *best_mode) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci if (idlemodes & BIT(SYSC_IDLE_SMART_WKUP)) 11788c2ecf20Sopenharmony_ci *best_mode = SYSC_IDLE_SMART_WKUP; 11798c2ecf20Sopenharmony_ci else if (idlemodes & BIT(SYSC_IDLE_SMART)) 11808c2ecf20Sopenharmony_ci *best_mode = SYSC_IDLE_SMART; 11818c2ecf20Sopenharmony_ci else if (idlemodes & BIT(SYSC_IDLE_FORCE)) 11828c2ecf20Sopenharmony_ci *best_mode = SYSC_IDLE_FORCE; 11838c2ecf20Sopenharmony_ci else 11848c2ecf20Sopenharmony_ci return -EINVAL; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci/* Caller needs to manage sysc_clkdm_deny_idle() and sysc_clkdm_allow_idle() */ 11908c2ecf20Sopenharmony_cistatic int sysc_disable_module(struct device *dev) 11918c2ecf20Sopenharmony_ci{ 11928c2ecf20Sopenharmony_ci struct sysc *ddata; 11938c2ecf20Sopenharmony_ci const struct sysc_regbits *regbits; 11948c2ecf20Sopenharmony_ci u32 reg, idlemodes, best_mode; 11958c2ecf20Sopenharmony_ci int ret; 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 11988c2ecf20Sopenharmony_ci if (ddata->offsets[SYSC_SYSCONFIG] == -ENODEV) 11998c2ecf20Sopenharmony_ci return 0; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci if (ddata->module_disable_quirk) 12028c2ecf20Sopenharmony_ci ddata->module_disable_quirk(ddata); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci regbits = ddata->cap->regbits; 12058c2ecf20Sopenharmony_ci reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci /* Set MIDLE mode */ 12088c2ecf20Sopenharmony_ci idlemodes = ddata->cfg.midlemodes; 12098c2ecf20Sopenharmony_ci if (!idlemodes || regbits->midle_shift < 0) 12108c2ecf20Sopenharmony_ci goto set_sidle; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci ret = sysc_best_idle_mode(idlemodes, &best_mode); 12138c2ecf20Sopenharmony_ci if (ret) { 12148c2ecf20Sopenharmony_ci dev_err(dev, "%s: invalid midlemode\n", __func__); 12158c2ecf20Sopenharmony_ci return ret; 12168c2ecf20Sopenharmony_ci } 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_MSTANDBY) || 12198c2ecf20Sopenharmony_ci ddata->cfg.quirks & (SYSC_QUIRK_FORCE_MSTANDBY)) 12208c2ecf20Sopenharmony_ci best_mode = SYSC_IDLE_FORCE; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); 12238c2ecf20Sopenharmony_ci reg |= best_mode << regbits->midle_shift; 12248c2ecf20Sopenharmony_ci sysc_write_sysconfig(ddata, reg); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ciset_sidle: 12278c2ecf20Sopenharmony_ci /* Set SIDLE mode */ 12288c2ecf20Sopenharmony_ci idlemodes = ddata->cfg.sidlemodes; 12298c2ecf20Sopenharmony_ci if (!idlemodes || regbits->sidle_shift < 0) 12308c2ecf20Sopenharmony_ci return 0; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE) { 12338c2ecf20Sopenharmony_ci best_mode = SYSC_IDLE_FORCE; 12348c2ecf20Sopenharmony_ci } else { 12358c2ecf20Sopenharmony_ci ret = sysc_best_idle_mode(idlemodes, &best_mode); 12368c2ecf20Sopenharmony_ci if (ret) { 12378c2ecf20Sopenharmony_ci dev_err(dev, "%s: invalid sidlemode\n", __func__); 12388c2ecf20Sopenharmony_ci return ret; 12398c2ecf20Sopenharmony_ci } 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT) { 12438c2ecf20Sopenharmony_ci /* Set WAKEUP */ 12448c2ecf20Sopenharmony_ci if (regbits->enwkup_shift >= 0 && 12458c2ecf20Sopenharmony_ci ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) 12468c2ecf20Sopenharmony_ci reg |= BIT(regbits->enwkup_shift); 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); 12508c2ecf20Sopenharmony_ci reg |= best_mode << regbits->sidle_shift; 12518c2ecf20Sopenharmony_ci if (regbits->autoidle_shift >= 0 && 12528c2ecf20Sopenharmony_ci ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) 12538c2ecf20Sopenharmony_ci reg |= 1 << regbits->autoidle_shift; 12548c2ecf20Sopenharmony_ci sysc_write_sysconfig(ddata, reg); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* Flush posted write */ 12578c2ecf20Sopenharmony_ci sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci return 0; 12608c2ecf20Sopenharmony_ci} 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_runtime_suspend_legacy(struct device *dev, 12638c2ecf20Sopenharmony_ci struct sysc *ddata) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata; 12668c2ecf20Sopenharmony_ci int error; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci pdata = dev_get_platdata(ddata->dev); 12698c2ecf20Sopenharmony_ci if (!pdata) 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci if (!pdata->idle_module) 12738c2ecf20Sopenharmony_ci return -ENODEV; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci error = pdata->idle_module(dev, &ddata->cookie); 12768c2ecf20Sopenharmony_ci if (error) 12778c2ecf20Sopenharmony_ci dev_err(dev, "%s: could not idle: %i\n", 12788c2ecf20Sopenharmony_ci __func__, error); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci reset_control_assert(ddata->rsts); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci return 0; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_runtime_resume_legacy(struct device *dev, 12868c2ecf20Sopenharmony_ci struct sysc *ddata) 12878c2ecf20Sopenharmony_ci{ 12888c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata; 12898c2ecf20Sopenharmony_ci int error; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci pdata = dev_get_platdata(ddata->dev); 12928c2ecf20Sopenharmony_ci if (!pdata) 12938c2ecf20Sopenharmony_ci return 0; 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci if (!pdata->enable_module) 12968c2ecf20Sopenharmony_ci return -ENODEV; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci error = pdata->enable_module(dev, &ddata->cookie); 12998c2ecf20Sopenharmony_ci if (error) 13008c2ecf20Sopenharmony_ci dev_err(dev, "%s: could not enable: %i\n", 13018c2ecf20Sopenharmony_ci __func__, error); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci reset_control_deassert(ddata->rsts); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return 0; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_runtime_suspend(struct device *dev) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci struct sysc *ddata; 13118c2ecf20Sopenharmony_ci int error = 0; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (!ddata->enabled) 13168c2ecf20Sopenharmony_ci return 0; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci sysc_clkdm_deny_idle(ddata); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (ddata->legacy_mode) { 13218c2ecf20Sopenharmony_ci error = sysc_runtime_suspend_legacy(dev, ddata); 13228c2ecf20Sopenharmony_ci if (error) 13238c2ecf20Sopenharmony_ci goto err_allow_idle; 13248c2ecf20Sopenharmony_ci } else { 13258c2ecf20Sopenharmony_ci error = sysc_disable_module(dev); 13268c2ecf20Sopenharmony_ci if (error) 13278c2ecf20Sopenharmony_ci goto err_allow_idle; 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci sysc_disable_main_clocks(ddata); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if (sysc_opt_clks_needed(ddata)) 13338c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci ddata->enabled = false; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_cierr_allow_idle: 13388c2ecf20Sopenharmony_ci reset_control_assert(ddata->rsts); 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci return error; 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_runtime_resume(struct device *dev) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci struct sysc *ddata; 13488c2ecf20Sopenharmony_ci int error = 0; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci if (ddata->enabled) 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci sysc_clkdm_deny_idle(ddata); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci if (sysc_opt_clks_needed(ddata)) { 13598c2ecf20Sopenharmony_ci error = sysc_enable_opt_clocks(ddata); 13608c2ecf20Sopenharmony_ci if (error) 13618c2ecf20Sopenharmony_ci goto err_allow_idle; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci error = sysc_enable_main_clocks(ddata); 13658c2ecf20Sopenharmony_ci if (error) 13668c2ecf20Sopenharmony_ci goto err_opt_clocks; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci reset_control_deassert(ddata->rsts); 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci if (ddata->legacy_mode) { 13718c2ecf20Sopenharmony_ci error = sysc_runtime_resume_legacy(dev, ddata); 13728c2ecf20Sopenharmony_ci if (error) 13738c2ecf20Sopenharmony_ci goto err_main_clocks; 13748c2ecf20Sopenharmony_ci } else { 13758c2ecf20Sopenharmony_ci error = sysc_enable_module(dev); 13768c2ecf20Sopenharmony_ci if (error) 13778c2ecf20Sopenharmony_ci goto err_main_clocks; 13788c2ecf20Sopenharmony_ci } 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci ddata->enabled = true; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci return 0; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_cierr_main_clocks: 13878c2ecf20Sopenharmony_ci sysc_disable_main_clocks(ddata); 13888c2ecf20Sopenharmony_cierr_opt_clocks: 13898c2ecf20Sopenharmony_ci if (sysc_opt_clks_needed(ddata)) 13908c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 13918c2ecf20Sopenharmony_cierr_allow_idle: 13928c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return error; 13958c2ecf20Sopenharmony_ci} 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_cistatic int sysc_reinit_module(struct sysc *ddata, bool leave_enabled) 13988c2ecf20Sopenharmony_ci{ 13998c2ecf20Sopenharmony_ci struct device *dev = ddata->dev; 14008c2ecf20Sopenharmony_ci int error; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci /* Disable target module if it is enabled */ 14038c2ecf20Sopenharmony_ci if (ddata->enabled) { 14048c2ecf20Sopenharmony_ci error = sysc_runtime_suspend(dev); 14058c2ecf20Sopenharmony_ci if (error) 14068c2ecf20Sopenharmony_ci dev_warn(dev, "reinit suspend failed: %i\n", error); 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* Enable target module */ 14108c2ecf20Sopenharmony_ci error = sysc_runtime_resume(dev); 14118c2ecf20Sopenharmony_ci if (error) 14128c2ecf20Sopenharmony_ci dev_warn(dev, "reinit resume failed: %i\n", error); 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci if (leave_enabled) 14158c2ecf20Sopenharmony_ci return error; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci /* Disable target module if no leave_enabled was set */ 14188c2ecf20Sopenharmony_ci error = sysc_runtime_suspend(dev); 14198c2ecf20Sopenharmony_ci if (error) 14208c2ecf20Sopenharmony_ci dev_warn(dev, "reinit suspend failed: %i\n", error); 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci return error; 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_noirq_suspend(struct device *dev) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct sysc *ddata; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & 14328c2ecf20Sopenharmony_ci (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE)) 14338c2ecf20Sopenharmony_ci return 0; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (!ddata->enabled) 14368c2ecf20Sopenharmony_ci return 0; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci ddata->needs_resume = 1; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci return sysc_runtime_suspend(dev); 14418c2ecf20Sopenharmony_ci} 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_noirq_resume(struct device *dev) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct sysc *ddata; 14468c2ecf20Sopenharmony_ci int error = 0; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci ddata = dev_get_drvdata(dev); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & 14518c2ecf20Sopenharmony_ci (SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_NO_IDLE)) 14528c2ecf20Sopenharmony_ci return 0; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_RESUME) { 14558c2ecf20Sopenharmony_ci error = sysc_reinit_module(ddata, ddata->needs_resume); 14568c2ecf20Sopenharmony_ci if (error) 14578c2ecf20Sopenharmony_ci dev_warn(dev, "noirq_resume failed: %i\n", error); 14588c2ecf20Sopenharmony_ci } else if (ddata->needs_resume) { 14598c2ecf20Sopenharmony_ci error = sysc_runtime_resume(dev); 14608c2ecf20Sopenharmony_ci if (error) 14618c2ecf20Sopenharmony_ci dev_warn(dev, "noirq_resume failed: %i\n", error); 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci ddata->needs_resume = 0; 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci return error; 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sysc_pm_ops = { 14708c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume) 14718c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(sysc_runtime_suspend, 14728c2ecf20Sopenharmony_ci sysc_runtime_resume, 14738c2ecf20Sopenharmony_ci NULL) 14748c2ecf20Sopenharmony_ci}; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci/* Module revision register based quirks */ 14778c2ecf20Sopenharmony_cistruct sysc_revision_quirk { 14788c2ecf20Sopenharmony_ci const char *name; 14798c2ecf20Sopenharmony_ci u32 base; 14808c2ecf20Sopenharmony_ci int rev_offset; 14818c2ecf20Sopenharmony_ci int sysc_offset; 14828c2ecf20Sopenharmony_ci int syss_offset; 14838c2ecf20Sopenharmony_ci u32 revision; 14848c2ecf20Sopenharmony_ci u32 revision_mask; 14858c2ecf20Sopenharmony_ci u32 quirks; 14868c2ecf20Sopenharmony_ci}; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci#define SYSC_QUIRK(optname, optbase, optrev, optsysc, optsyss, \ 14898c2ecf20Sopenharmony_ci optrev_val, optrevmask, optquirkmask) \ 14908c2ecf20Sopenharmony_ci { \ 14918c2ecf20Sopenharmony_ci .name = (optname), \ 14928c2ecf20Sopenharmony_ci .base = (optbase), \ 14938c2ecf20Sopenharmony_ci .rev_offset = (optrev), \ 14948c2ecf20Sopenharmony_ci .sysc_offset = (optsysc), \ 14958c2ecf20Sopenharmony_ci .syss_offset = (optsyss), \ 14968c2ecf20Sopenharmony_ci .revision = (optrev_val), \ 14978c2ecf20Sopenharmony_ci .revision_mask = (optrevmask), \ 14988c2ecf20Sopenharmony_ci .quirks = (optquirkmask), \ 14998c2ecf20Sopenharmony_ci } 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_cistatic const struct sysc_revision_quirk sysc_revision_quirks[] = { 15028c2ecf20Sopenharmony_ci /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ 15038c2ecf20Sopenharmony_ci SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff, 15048c2ecf20Sopenharmony_ci SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), 15058c2ecf20Sopenharmony_ci SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, 15068c2ecf20Sopenharmony_ci SYSC_QUIRK_LEGACY_IDLE), 15078c2ecf20Sopenharmony_ci SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, 15088c2ecf20Sopenharmony_ci SYSC_QUIRK_LEGACY_IDLE), 15098c2ecf20Sopenharmony_ci SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, 15108c2ecf20Sopenharmony_ci SYSC_QUIRK_LEGACY_IDLE), 15118c2ecf20Sopenharmony_ci SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, 15128c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), 15138c2ecf20Sopenharmony_ci SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, 15148c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), 15158c2ecf20Sopenharmony_ci /* Uarts on omap4 and later */ 15168c2ecf20Sopenharmony_ci SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff, 15178c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), 15188c2ecf20Sopenharmony_ci SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff, 15198c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), 15208c2ecf20Sopenharmony_ci SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff, 15218c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci /* Quirks that need to be set based on the module address */ 15248c2ecf20Sopenharmony_ci SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff, 15258c2ecf20Sopenharmony_ci SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT | 15268c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE), 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* Quirks that need to be set based on detected module */ 15298c2ecf20Sopenharmony_ci SYSC_QUIRK("aess", 0, 0, 0x10, -ENODEV, 0x40000000, 0xffffffff, 15308c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_AESS), 15318c2ecf20Sopenharmony_ci /* Errata i893 handling for dra7 dcan1 and 2 */ 15328c2ecf20Sopenharmony_ci SYSC_QUIRK("dcan", 0x4ae3c000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 15338c2ecf20Sopenharmony_ci SYSC_QUIRK_CLKDM_NOAUTO), 15348c2ecf20Sopenharmony_ci SYSC_QUIRK("dcan", 0x48480000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 15358c2ecf20Sopenharmony_ci SYSC_QUIRK_CLKDM_NOAUTO), 15368c2ecf20Sopenharmony_ci SYSC_QUIRK("dss", 0x4832a000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 15378c2ecf20Sopenharmony_ci SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), 15388c2ecf20Sopenharmony_ci SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000040, 0xffffffff, 15398c2ecf20Sopenharmony_ci SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), 15408c2ecf20Sopenharmony_ci SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000061, 0xffffffff, 15418c2ecf20Sopenharmony_ci SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), 15428c2ecf20Sopenharmony_ci SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 15438c2ecf20Sopenharmony_ci SYSC_QUIRK_CLKDM_NOAUTO), 15448c2ecf20Sopenharmony_ci SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 15458c2ecf20Sopenharmony_ci SYSC_QUIRK_CLKDM_NOAUTO), 15468c2ecf20Sopenharmony_ci SYSC_QUIRK("gpmc", 0, 0, 0x10, 0x14, 0x00000060, 0xffffffff, 15478c2ecf20Sopenharmony_ci SYSC_QUIRK_GPMC_DEBUG), 15488c2ecf20Sopenharmony_ci SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff, 15498c2ecf20Sopenharmony_ci SYSC_QUIRK_OPT_CLKS_NEEDED), 15508c2ecf20Sopenharmony_ci SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 15518c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_HDQ1W | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15528c2ecf20Sopenharmony_ci SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 15538c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_HDQ1W | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15548c2ecf20Sopenharmony_ci SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000036, 0x000000ff, 15558c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15568c2ecf20Sopenharmony_ci SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x0000003c, 0x000000ff, 15578c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15588c2ecf20Sopenharmony_ci SYSC_QUIRK("i2c", 0, 0, 0x20, 0x10, 0x00000040, 0x000000ff, 15598c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15608c2ecf20Sopenharmony_ci SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 15618c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_I2C | SYSC_MODULE_QUIRK_ENA_RESETDONE), 15628c2ecf20Sopenharmony_ci SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0), 15638c2ecf20Sopenharmony_ci SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 15648c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_SGX), 15658c2ecf20Sopenharmony_ci SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff, 15668c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15678c2ecf20Sopenharmony_ci SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0, 15688c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_RTC_UNLOCK), 15698c2ecf20Sopenharmony_ci SYSC_QUIRK("tptc", 0, 0, 0x10, -ENODEV, 0x40006c00, 0xffffefff, 15708c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15718c2ecf20Sopenharmony_ci SYSC_QUIRK("tptc", 0, 0, -ENODEV, -ENODEV, 0x40007c00, 0xffffffff, 15728c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15738c2ecf20Sopenharmony_ci SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 15748c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15758c2ecf20Sopenharmony_ci SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff, 15768c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15778c2ecf20Sopenharmony_ci SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, 15788c2ecf20Sopenharmony_ci 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), 15798c2ecf20Sopenharmony_ci SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff, 15808c2ecf20Sopenharmony_ci SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY | 15818c2ecf20Sopenharmony_ci SYSC_QUIRK_REINIT_ON_CTX_LOST), 15828c2ecf20Sopenharmony_ci SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 15838c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_WDT), 15848c2ecf20Sopenharmony_ci /* PRUSS on am3, am4 and am5 */ 15858c2ecf20Sopenharmony_ci SYSC_QUIRK("pruss", 0, 0x26000, 0x26004, -ENODEV, 0x47000000, 0xff000000, 15868c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_PRUSS), 15878c2ecf20Sopenharmony_ci /* Watchdog on am3 and am4 */ 15888c2ecf20Sopenharmony_ci SYSC_QUIRK("wdt", 0x44e35000, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 15898c2ecf20Sopenharmony_ci SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE), 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci#ifdef DEBUG 15928c2ecf20Sopenharmony_ci SYSC_QUIRK("adc", 0, 0, 0x10, -ENODEV, 0x47300001, 0xffffffff, 0), 15938c2ecf20Sopenharmony_ci SYSC_QUIRK("atl", 0, 0, -ENODEV, -ENODEV, 0x0a070100, 0xffffffff, 0), 15948c2ecf20Sopenharmony_ci SYSC_QUIRK("cm", 0, 0, -ENODEV, -ENODEV, 0x40000301, 0xffffffff, 0), 15958c2ecf20Sopenharmony_ci SYSC_QUIRK("control", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), 15968c2ecf20Sopenharmony_ci SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902, 15978c2ecf20Sopenharmony_ci 0xffff00f0, 0), 15988c2ecf20Sopenharmony_ci SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 0), 15998c2ecf20Sopenharmony_ci SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0x4edb1902, 0xffffffff, 0), 16008c2ecf20Sopenharmony_ci SYSC_QUIRK("dispc", 0x4832a400, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), 16018c2ecf20Sopenharmony_ci SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), 16028c2ecf20Sopenharmony_ci SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000051, 0xffffffff, 0), 16038c2ecf20Sopenharmony_ci SYSC_QUIRK("dmic", 0, 0, 0x10, -ENODEV, 0x50010000, 0xffffffff, 0), 16048c2ecf20Sopenharmony_ci SYSC_QUIRK("dsi", 0x58004000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), 16058c2ecf20Sopenharmony_ci SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), 16068c2ecf20Sopenharmony_ci SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), 16078c2ecf20Sopenharmony_ci SYSC_QUIRK("dsi", 0x58009000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), 16088c2ecf20Sopenharmony_ci SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0), 16098c2ecf20Sopenharmony_ci SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), 16108c2ecf20Sopenharmony_ci SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), 16118c2ecf20Sopenharmony_ci SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0), 16128c2ecf20Sopenharmony_ci SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0), 16138c2ecf20Sopenharmony_ci SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0), 16148c2ecf20Sopenharmony_ci SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50031d00, 0xffffffff, 0), 16158c2ecf20Sopenharmony_ci SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), 16168c2ecf20Sopenharmony_ci SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0), 16178c2ecf20Sopenharmony_ci SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0), 16188c2ecf20Sopenharmony_ci SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0), 16198c2ecf20Sopenharmony_ci SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0), 16208c2ecf20Sopenharmony_ci SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0), 16218c2ecf20Sopenharmony_ci SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0), 16228c2ecf20Sopenharmony_ci SYSC_QUIRK("mailbox", 0, 0, 0x10, -ENODEV, 0x00000400, 0xffffffff, 0), 16238c2ecf20Sopenharmony_ci SYSC_QUIRK("m3", 0, 0, -ENODEV, -ENODEV, 0x5f580105, 0x0fff0f00, 0), 16248c2ecf20Sopenharmony_ci SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), 16258c2ecf20Sopenharmony_ci SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0), 16268c2ecf20Sopenharmony_ci SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0), 16278c2ecf20Sopenharmony_ci SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0), 16288c2ecf20Sopenharmony_ci SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0), 16298c2ecf20Sopenharmony_ci SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0), 16308c2ecf20Sopenharmony_ci SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0), 16318c2ecf20Sopenharmony_ci SYSC_QUIRK("rfbi", 0x4832a800, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), 16328c2ecf20Sopenharmony_ci SYSC_QUIRK("rfbi", 0x58002000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), 16338c2ecf20Sopenharmony_ci SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), 16348c2ecf20Sopenharmony_ci SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0), 16358c2ecf20Sopenharmony_ci SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0), 16368c2ecf20Sopenharmony_ci SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x40000900, 0xffffffff, 0), 16378c2ecf20Sopenharmony_ci SYSC_QUIRK("scrm", 0, 0, -ENODEV, -ENODEV, 0x00000010, 0xffffffff, 0), 16388c2ecf20Sopenharmony_ci SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0), 16398c2ecf20Sopenharmony_ci SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0), 16408c2ecf20Sopenharmony_ci SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0), 16418c2ecf20Sopenharmony_ci SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0), 16428c2ecf20Sopenharmony_ci SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0), 16438c2ecf20Sopenharmony_ci SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0), 16448c2ecf20Sopenharmony_ci SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0), 16458c2ecf20Sopenharmony_ci SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000013, 0xffffffff, 0), 16468c2ecf20Sopenharmony_ci SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, 0), 16478c2ecf20Sopenharmony_ci /* Some timers on omap4 and later */ 16488c2ecf20Sopenharmony_ci SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff, 0), 16498c2ecf20Sopenharmony_ci SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff, 0), 16508c2ecf20Sopenharmony_ci SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000040, 0xffffffff, 0), 16518c2ecf20Sopenharmony_ci SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000011, 0xffffffff, 0), 16528c2ecf20Sopenharmony_ci SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0), 16538c2ecf20Sopenharmony_ci SYSC_QUIRK("tpcc", 0, 0, -ENODEV, -ENODEV, 0x40014c00, 0xffffffff, 0), 16548c2ecf20Sopenharmony_ci SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), 16558c2ecf20Sopenharmony_ci SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0), 16568c2ecf20Sopenharmony_ci SYSC_QUIRK("venc", 0x58003000, 0, -ENODEV, -ENODEV, 0x00000002, 0xffffffff, 0), 16578c2ecf20Sopenharmony_ci SYSC_QUIRK("vfpe", 0, 0, 0x104, -ENODEV, 0x4d001200, 0xffffffff, 0), 16588c2ecf20Sopenharmony_ci#endif 16598c2ecf20Sopenharmony_ci}; 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci/* 16628c2ecf20Sopenharmony_ci * Early quirks based on module base and register offsets only that are 16638c2ecf20Sopenharmony_ci * needed before the module revision can be read 16648c2ecf20Sopenharmony_ci */ 16658c2ecf20Sopenharmony_cistatic void sysc_init_early_quirks(struct sysc *ddata) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci const struct sysc_revision_quirk *q; 16688c2ecf20Sopenharmony_ci int i; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) { 16718c2ecf20Sopenharmony_ci q = &sysc_revision_quirks[i]; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (!q->base) 16748c2ecf20Sopenharmony_ci continue; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci if (q->base != ddata->module_pa) 16778c2ecf20Sopenharmony_ci continue; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci if (q->rev_offset != ddata->offsets[SYSC_REVISION]) 16808c2ecf20Sopenharmony_ci continue; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) 16838c2ecf20Sopenharmony_ci continue; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) 16868c2ecf20Sopenharmony_ci continue; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci ddata->name = q->name; 16898c2ecf20Sopenharmony_ci ddata->cfg.quirks |= q->quirks; 16908c2ecf20Sopenharmony_ci } 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci/* Quirks that also consider the revision register value */ 16948c2ecf20Sopenharmony_cistatic void sysc_init_revision_quirks(struct sysc *ddata) 16958c2ecf20Sopenharmony_ci{ 16968c2ecf20Sopenharmony_ci const struct sysc_revision_quirk *q; 16978c2ecf20Sopenharmony_ci int i; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sysc_revision_quirks); i++) { 17008c2ecf20Sopenharmony_ci q = &sysc_revision_quirks[i]; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci if (q->base && q->base != ddata->module_pa) 17038c2ecf20Sopenharmony_ci continue; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci if (q->rev_offset != ddata->offsets[SYSC_REVISION]) 17068c2ecf20Sopenharmony_ci continue; 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) 17098c2ecf20Sopenharmony_ci continue; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) 17128c2ecf20Sopenharmony_ci continue; 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci if (q->revision == ddata->revision || 17158c2ecf20Sopenharmony_ci (q->revision & q->revision_mask) == 17168c2ecf20Sopenharmony_ci (ddata->revision & q->revision_mask)) { 17178c2ecf20Sopenharmony_ci ddata->name = q->name; 17188c2ecf20Sopenharmony_ci ddata->cfg.quirks |= q->quirks; 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci } 17218c2ecf20Sopenharmony_ci} 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci/* 17248c2ecf20Sopenharmony_ci * DSS needs dispc outputs disabled to reset modules. Returns mask of 17258c2ecf20Sopenharmony_ci * enabled DSS interrupts. Eventually we may be able to do this on 17268c2ecf20Sopenharmony_ci * dispc init rather than top-level DSS init. 17278c2ecf20Sopenharmony_ci */ 17288c2ecf20Sopenharmony_cistatic u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, 17298c2ecf20Sopenharmony_ci bool disable) 17308c2ecf20Sopenharmony_ci{ 17318c2ecf20Sopenharmony_ci bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false; 17328c2ecf20Sopenharmony_ci const int lcd_en_mask = BIT(0), digit_en_mask = BIT(1); 17338c2ecf20Sopenharmony_ci int manager_count; 17348c2ecf20Sopenharmony_ci bool framedonetv_irq = true; 17358c2ecf20Sopenharmony_ci u32 val, irq_mask = 0; 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci switch (sysc_soc->soc) { 17388c2ecf20Sopenharmony_ci case SOC_2420 ... SOC_3630: 17398c2ecf20Sopenharmony_ci manager_count = 2; 17408c2ecf20Sopenharmony_ci framedonetv_irq = false; 17418c2ecf20Sopenharmony_ci break; 17428c2ecf20Sopenharmony_ci case SOC_4430 ... SOC_4470: 17438c2ecf20Sopenharmony_ci manager_count = 3; 17448c2ecf20Sopenharmony_ci break; 17458c2ecf20Sopenharmony_ci case SOC_5430: 17468c2ecf20Sopenharmony_ci case SOC_DRA7: 17478c2ecf20Sopenharmony_ci manager_count = 4; 17488c2ecf20Sopenharmony_ci break; 17498c2ecf20Sopenharmony_ci case SOC_AM4: 17508c2ecf20Sopenharmony_ci manager_count = 1; 17518c2ecf20Sopenharmony_ci framedonetv_irq = false; 17528c2ecf20Sopenharmony_ci break; 17538c2ecf20Sopenharmony_ci case SOC_UNKNOWN: 17548c2ecf20Sopenharmony_ci default: 17558c2ecf20Sopenharmony_ci return 0; 17568c2ecf20Sopenharmony_ci }; 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* Remap the whole module range to be able to reset dispc outputs */ 17598c2ecf20Sopenharmony_ci devm_iounmap(ddata->dev, ddata->module_va); 17608c2ecf20Sopenharmony_ci ddata->module_va = devm_ioremap(ddata->dev, 17618c2ecf20Sopenharmony_ci ddata->module_pa, 17628c2ecf20Sopenharmony_ci ddata->module_size); 17638c2ecf20Sopenharmony_ci if (!ddata->module_va) 17648c2ecf20Sopenharmony_ci return -EIO; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci /* DISP_CONTROL, shut down lcd and digit on disable if enabled */ 17678c2ecf20Sopenharmony_ci val = sysc_read(ddata, dispc_offset + 0x40); 17688c2ecf20Sopenharmony_ci lcd_en = val & lcd_en_mask; 17698c2ecf20Sopenharmony_ci digit_en = val & digit_en_mask; 17708c2ecf20Sopenharmony_ci if (lcd_en) 17718c2ecf20Sopenharmony_ci irq_mask |= BIT(0); /* FRAMEDONE */ 17728c2ecf20Sopenharmony_ci if (digit_en) { 17738c2ecf20Sopenharmony_ci if (framedonetv_irq) 17748c2ecf20Sopenharmony_ci irq_mask |= BIT(24); /* FRAMEDONETV */ 17758c2ecf20Sopenharmony_ci else 17768c2ecf20Sopenharmony_ci irq_mask |= BIT(2) | BIT(3); /* EVSYNC bits */ 17778c2ecf20Sopenharmony_ci } 17788c2ecf20Sopenharmony_ci if (disable && (lcd_en || digit_en)) 17798c2ecf20Sopenharmony_ci sysc_write(ddata, dispc_offset + 0x40, 17808c2ecf20Sopenharmony_ci val & ~(lcd_en_mask | digit_en_mask)); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci if (manager_count <= 2) 17838c2ecf20Sopenharmony_ci return irq_mask; 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci /* DISPC_CONTROL2 */ 17868c2ecf20Sopenharmony_ci val = sysc_read(ddata, dispc_offset + 0x238); 17878c2ecf20Sopenharmony_ci lcd2_en = val & lcd_en_mask; 17888c2ecf20Sopenharmony_ci if (lcd2_en) 17898c2ecf20Sopenharmony_ci irq_mask |= BIT(22); /* FRAMEDONE2 */ 17908c2ecf20Sopenharmony_ci if (disable && lcd2_en) 17918c2ecf20Sopenharmony_ci sysc_write(ddata, dispc_offset + 0x238, 17928c2ecf20Sopenharmony_ci val & ~lcd_en_mask); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (manager_count <= 3) 17958c2ecf20Sopenharmony_ci return irq_mask; 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci /* DISPC_CONTROL3 */ 17988c2ecf20Sopenharmony_ci val = sysc_read(ddata, dispc_offset + 0x848); 17998c2ecf20Sopenharmony_ci lcd3_en = val & lcd_en_mask; 18008c2ecf20Sopenharmony_ci if (lcd3_en) 18018c2ecf20Sopenharmony_ci irq_mask |= BIT(30); /* FRAMEDONE3 */ 18028c2ecf20Sopenharmony_ci if (disable && lcd3_en) 18038c2ecf20Sopenharmony_ci sysc_write(ddata, dispc_offset + 0x848, 18048c2ecf20Sopenharmony_ci val & ~lcd_en_mask); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci return irq_mask; 18078c2ecf20Sopenharmony_ci} 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci/* DSS needs child outputs disabled and SDI registers cleared for reset */ 18108c2ecf20Sopenharmony_cistatic void sysc_pre_reset_quirk_dss(struct sysc *ddata) 18118c2ecf20Sopenharmony_ci{ 18128c2ecf20Sopenharmony_ci const int dispc_offset = 0x1000; 18138c2ecf20Sopenharmony_ci int error; 18148c2ecf20Sopenharmony_ci u32 irq_mask, val; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci /* Get enabled outputs */ 18178c2ecf20Sopenharmony_ci irq_mask = sysc_quirk_dispc(ddata, dispc_offset, false); 18188c2ecf20Sopenharmony_ci if (!irq_mask) 18198c2ecf20Sopenharmony_ci return; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Clear IRQSTATUS */ 18228c2ecf20Sopenharmony_ci sysc_write(ddata, dispc_offset + 0x18, irq_mask); 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci /* Disable outputs */ 18258c2ecf20Sopenharmony_ci val = sysc_quirk_dispc(ddata, dispc_offset, true); 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci /* Poll IRQSTATUS */ 18288c2ecf20Sopenharmony_ci error = readl_poll_timeout(ddata->module_va + dispc_offset + 0x18, 18298c2ecf20Sopenharmony_ci val, val != irq_mask, 100, 50); 18308c2ecf20Sopenharmony_ci if (error) 18318c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "%s: timed out %08x !+ %08x\n", 18328c2ecf20Sopenharmony_ci __func__, val, irq_mask); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) { 18358c2ecf20Sopenharmony_ci /* Clear DSS_SDI_CONTROL */ 18368c2ecf20Sopenharmony_ci sysc_write(ddata, 0x44, 0); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci /* Clear DSS_PLL_CONTROL */ 18398c2ecf20Sopenharmony_ci sysc_write(ddata, 0x48, 0); 18408c2ecf20Sopenharmony_ci } 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci /* Clear DSS_CONTROL to switch DSS clock sources to PRCM if not */ 18438c2ecf20Sopenharmony_ci sysc_write(ddata, 0x40, 0); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci/* 1-wire needs module's internal clocks enabled for reset */ 18478c2ecf20Sopenharmony_cistatic void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata) 18488c2ecf20Sopenharmony_ci{ 18498c2ecf20Sopenharmony_ci int offset = 0x0c; /* HDQ_CTRL_STATUS */ 18508c2ecf20Sopenharmony_ci u16 val; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci val = sysc_read(ddata, offset); 18538c2ecf20Sopenharmony_ci val |= BIT(5); 18548c2ecf20Sopenharmony_ci sysc_write(ddata, offset, val); 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci/* AESS (Audio Engine SubSystem) needs autogating set after enable */ 18588c2ecf20Sopenharmony_cistatic void sysc_module_enable_quirk_aess(struct sysc *ddata) 18598c2ecf20Sopenharmony_ci{ 18608c2ecf20Sopenharmony_ci int offset = 0x7c; /* AESS_AUTO_GATING_ENABLE */ 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci sysc_write(ddata, offset, 1); 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci/* I2C needs to be disabled for reset */ 18668c2ecf20Sopenharmony_cistatic void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci int offset; 18698c2ecf20Sopenharmony_ci u16 val; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci /* I2C_CON, omap2/3 is different from omap4 and later */ 18728c2ecf20Sopenharmony_ci if ((ddata->revision & 0xffffff00) == 0x001f0000) 18738c2ecf20Sopenharmony_ci offset = 0x24; 18748c2ecf20Sopenharmony_ci else 18758c2ecf20Sopenharmony_ci offset = 0xa4; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci /* I2C_EN */ 18788c2ecf20Sopenharmony_ci val = sysc_read(ddata, offset); 18798c2ecf20Sopenharmony_ci if (enable) 18808c2ecf20Sopenharmony_ci val |= BIT(15); 18818c2ecf20Sopenharmony_ci else 18828c2ecf20Sopenharmony_ci val &= ~BIT(15); 18838c2ecf20Sopenharmony_ci sysc_write(ddata, offset, val); 18848c2ecf20Sopenharmony_ci} 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cistatic void sysc_pre_reset_quirk_i2c(struct sysc *ddata) 18878c2ecf20Sopenharmony_ci{ 18888c2ecf20Sopenharmony_ci sysc_clk_quirk_i2c(ddata, false); 18898c2ecf20Sopenharmony_ci} 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_cistatic void sysc_post_reset_quirk_i2c(struct sysc *ddata) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci sysc_clk_quirk_i2c(ddata, true); 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci/* RTC on am3 and 4 needs to be unlocked and locked for sysconfig */ 18978c2ecf20Sopenharmony_cistatic void sysc_quirk_rtc(struct sysc *ddata, bool lock) 18988c2ecf20Sopenharmony_ci{ 18998c2ecf20Sopenharmony_ci u32 val, kick0_val = 0, kick1_val = 0; 19008c2ecf20Sopenharmony_ci unsigned long flags; 19018c2ecf20Sopenharmony_ci int error; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci if (!lock) { 19048c2ecf20Sopenharmony_ci kick0_val = 0x83e70b13; 19058c2ecf20Sopenharmony_ci kick1_val = 0x95a4f1e0; 19068c2ecf20Sopenharmony_ci } 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci local_irq_save(flags); 19098c2ecf20Sopenharmony_ci /* RTC_STATUS BUSY bit may stay active for 1/32768 seconds (~30 usec) */ 19108c2ecf20Sopenharmony_ci error = readl_poll_timeout_atomic(ddata->module_va + 0x44, val, 19118c2ecf20Sopenharmony_ci !(val & BIT(0)), 100, 50); 19128c2ecf20Sopenharmony_ci if (error) 19138c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "rtc busy timeout\n"); 19148c2ecf20Sopenharmony_ci /* Now we have ~15 microseconds to read/write various registers */ 19158c2ecf20Sopenharmony_ci sysc_write(ddata, 0x6c, kick0_val); 19168c2ecf20Sopenharmony_ci sysc_write(ddata, 0x70, kick1_val); 19178c2ecf20Sopenharmony_ci local_irq_restore(flags); 19188c2ecf20Sopenharmony_ci} 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_cistatic void sysc_module_unlock_quirk_rtc(struct sysc *ddata) 19218c2ecf20Sopenharmony_ci{ 19228c2ecf20Sopenharmony_ci sysc_quirk_rtc(ddata, false); 19238c2ecf20Sopenharmony_ci} 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_cistatic void sysc_module_lock_quirk_rtc(struct sysc *ddata) 19268c2ecf20Sopenharmony_ci{ 19278c2ecf20Sopenharmony_ci sysc_quirk_rtc(ddata, true); 19288c2ecf20Sopenharmony_ci} 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ci/* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */ 19318c2ecf20Sopenharmony_cistatic void sysc_module_enable_quirk_sgx(struct sysc *ddata) 19328c2ecf20Sopenharmony_ci{ 19338c2ecf20Sopenharmony_ci int offset = 0xff08; /* OCP_DEBUG_CONFIG */ 19348c2ecf20Sopenharmony_ci u32 val = BIT(31); /* THALIA_INT_BYPASS */ 19358c2ecf20Sopenharmony_ci 19368c2ecf20Sopenharmony_ci sysc_write(ddata, offset, val); 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci/* Watchdog timer needs a disable sequence after reset */ 19408c2ecf20Sopenharmony_cistatic void sysc_reset_done_quirk_wdt(struct sysc *ddata) 19418c2ecf20Sopenharmony_ci{ 19428c2ecf20Sopenharmony_ci int wps, spr, error; 19438c2ecf20Sopenharmony_ci u32 val; 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci wps = 0x34; 19468c2ecf20Sopenharmony_ci spr = 0x48; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci sysc_write(ddata, spr, 0xaaaa); 19498c2ecf20Sopenharmony_ci error = readl_poll_timeout(ddata->module_va + wps, val, 19508c2ecf20Sopenharmony_ci !(val & 0x10), 100, 19518c2ecf20Sopenharmony_ci MAX_MODULE_SOFTRESET_WAIT); 19528c2ecf20Sopenharmony_ci if (error) 19538c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "wdt disable step1 failed\n"); 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci sysc_write(ddata, spr, 0x5555); 19568c2ecf20Sopenharmony_ci error = readl_poll_timeout(ddata->module_va + wps, val, 19578c2ecf20Sopenharmony_ci !(val & 0x10), 100, 19588c2ecf20Sopenharmony_ci MAX_MODULE_SOFTRESET_WAIT); 19598c2ecf20Sopenharmony_ci if (error) 19608c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "wdt disable step2 failed\n"); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci/* PRUSS needs to set MSTANDBY_INIT inorder to idle properly */ 19648c2ecf20Sopenharmony_cistatic void sysc_module_disable_quirk_pruss(struct sysc *ddata) 19658c2ecf20Sopenharmony_ci{ 19668c2ecf20Sopenharmony_ci u32 reg; 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ci reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); 19698c2ecf20Sopenharmony_ci reg |= SYSC_PRUSS_STANDBY_INIT; 19708c2ecf20Sopenharmony_ci sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic void sysc_init_module_quirks(struct sysc *ddata) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci if (ddata->legacy_mode || !ddata->name) 19768c2ecf20Sopenharmony_ci return; 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) { 19798c2ecf20Sopenharmony_ci ddata->pre_reset_quirk = sysc_pre_reset_quirk_hdq1w; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci return; 19828c2ecf20Sopenharmony_ci } 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci#ifdef CONFIG_OMAP_GPMC_DEBUG 19858c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_GPMC_DEBUG) { 19868c2ecf20Sopenharmony_ci ddata->cfg.quirks |= SYSC_QUIRK_NO_RESET_ON_INIT; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci return; 19898c2ecf20Sopenharmony_ci } 19908c2ecf20Sopenharmony_ci#endif 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) { 19938c2ecf20Sopenharmony_ci ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c; 19948c2ecf20Sopenharmony_ci ddata->post_reset_quirk = sysc_post_reset_quirk_i2c; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci return; 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS) 20008c2ecf20Sopenharmony_ci ddata->module_enable_quirk = sysc_module_enable_quirk_aess; 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_DSS_RESET) 20038c2ecf20Sopenharmony_ci ddata->pre_reset_quirk = sysc_pre_reset_quirk_dss; 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_RTC_UNLOCK) { 20068c2ecf20Sopenharmony_ci ddata->module_unlock_quirk = sysc_module_unlock_quirk_rtc; 20078c2ecf20Sopenharmony_ci ddata->module_lock_quirk = sysc_module_lock_quirk_rtc; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci return; 20108c2ecf20Sopenharmony_ci } 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX) 20138c2ecf20Sopenharmony_ci ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_WDT) { 20168c2ecf20Sopenharmony_ci ddata->reset_done_quirk = sysc_reset_done_quirk_wdt; 20178c2ecf20Sopenharmony_ci ddata->module_disable_quirk = sysc_reset_done_quirk_wdt; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_PRUSS) 20218c2ecf20Sopenharmony_ci ddata->module_disable_quirk = sysc_module_disable_quirk_pruss; 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic int sysc_clockdomain_init(struct sysc *ddata) 20258c2ecf20Sopenharmony_ci{ 20268c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); 20278c2ecf20Sopenharmony_ci struct clk *fck = NULL, *ick = NULL; 20288c2ecf20Sopenharmony_ci int error; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci if (!pdata || !pdata->init_clockdomain) 20318c2ecf20Sopenharmony_ci return 0; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci switch (ddata->nr_clocks) { 20348c2ecf20Sopenharmony_ci case 2: 20358c2ecf20Sopenharmony_ci ick = ddata->clocks[SYSC_ICK]; 20368c2ecf20Sopenharmony_ci fallthrough; 20378c2ecf20Sopenharmony_ci case 1: 20388c2ecf20Sopenharmony_ci fck = ddata->clocks[SYSC_FCK]; 20398c2ecf20Sopenharmony_ci break; 20408c2ecf20Sopenharmony_ci case 0: 20418c2ecf20Sopenharmony_ci return 0; 20428c2ecf20Sopenharmony_ci } 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci error = pdata->init_clockdomain(ddata->dev, fck, ick, &ddata->cookie); 20458c2ecf20Sopenharmony_ci if (!error || error == -ENODEV) 20468c2ecf20Sopenharmony_ci return 0; 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci return error; 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci/* 20528c2ecf20Sopenharmony_ci * Note that pdata->init_module() typically does a reset first. After 20538c2ecf20Sopenharmony_ci * pdata->init_module() is done, PM runtime can be used for the interconnect 20548c2ecf20Sopenharmony_ci * target module. 20558c2ecf20Sopenharmony_ci */ 20568c2ecf20Sopenharmony_cistatic int sysc_legacy_init(struct sysc *ddata) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); 20598c2ecf20Sopenharmony_ci int error; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci if (!pdata || !pdata->init_module) 20628c2ecf20Sopenharmony_ci return 0; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci error = pdata->init_module(ddata->dev, ddata->mdata, &ddata->cookie); 20658c2ecf20Sopenharmony_ci if (error == -EEXIST) 20668c2ecf20Sopenharmony_ci error = 0; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci return error; 20698c2ecf20Sopenharmony_ci} 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci/* 20728c2ecf20Sopenharmony_ci * Note that the caller must ensure the interconnect target module is enabled 20738c2ecf20Sopenharmony_ci * before calling reset. Otherwise reset will not complete. 20748c2ecf20Sopenharmony_ci */ 20758c2ecf20Sopenharmony_cistatic int sysc_reset(struct sysc *ddata) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci int sysc_offset, sysc_val, error; 20788c2ecf20Sopenharmony_ci u32 sysc_mask; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci if (ddata->legacy_mode || 20838c2ecf20Sopenharmony_ci ddata->cap->regbits->srst_shift < 0 || 20848c2ecf20Sopenharmony_ci ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) 20858c2ecf20Sopenharmony_ci return 0; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci sysc_mask = BIT(ddata->cap->regbits->srst_shift); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci if (ddata->pre_reset_quirk) 20908c2ecf20Sopenharmony_ci ddata->pre_reset_quirk(ddata); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci if (sysc_offset >= 0) { 20938c2ecf20Sopenharmony_ci sysc_val = sysc_read_sysconfig(ddata); 20948c2ecf20Sopenharmony_ci sysc_val |= sysc_mask; 20958c2ecf20Sopenharmony_ci sysc_write(ddata, sysc_offset, sysc_val); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci /* 20988c2ecf20Sopenharmony_ci * Some devices need a delay before reading registers 20998c2ecf20Sopenharmony_ci * after reset. Presumably a srst_udelay is not needed 21008c2ecf20Sopenharmony_ci * for devices that use a rstctrl register reset. 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_ci if (ddata->cfg.srst_udelay) 21038c2ecf20Sopenharmony_ci fsleep(ddata->cfg.srst_udelay); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci /* 21068c2ecf20Sopenharmony_ci * Flush posted write. For devices needing srst_udelay 21078c2ecf20Sopenharmony_ci * this should trigger an interconnect error if the 21088c2ecf20Sopenharmony_ci * srst_udelay value is needed but not configured. 21098c2ecf20Sopenharmony_ci */ 21108c2ecf20Sopenharmony_ci sysc_val = sysc_read_sysconfig(ddata); 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (ddata->post_reset_quirk) 21148c2ecf20Sopenharmony_ci ddata->post_reset_quirk(ddata); 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci error = sysc_wait_softreset(ddata); 21178c2ecf20Sopenharmony_ci if (error) 21188c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "OCP softreset timed out\n"); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (ddata->reset_done_quirk) 21218c2ecf20Sopenharmony_ci ddata->reset_done_quirk(ddata); 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci return error; 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci/* 21278c2ecf20Sopenharmony_ci * At this point the module is configured enough to read the revision but 21288c2ecf20Sopenharmony_ci * module may not be completely configured yet to use PM runtime. Enable 21298c2ecf20Sopenharmony_ci * all clocks directly during init to configure the quirks needed for PM 21308c2ecf20Sopenharmony_ci * runtime based on the revision register. 21318c2ecf20Sopenharmony_ci */ 21328c2ecf20Sopenharmony_cistatic int sysc_init_module(struct sysc *ddata) 21338c2ecf20Sopenharmony_ci{ 21348c2ecf20Sopenharmony_ci int error = 0; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci error = sysc_clockdomain_init(ddata); 21378c2ecf20Sopenharmony_ci if (error) 21388c2ecf20Sopenharmony_ci return error; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci sysc_clkdm_deny_idle(ddata); 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci /* 21438c2ecf20Sopenharmony_ci * Always enable clocks. The bootloader may or may not have enabled 21448c2ecf20Sopenharmony_ci * the related clocks. 21458c2ecf20Sopenharmony_ci */ 21468c2ecf20Sopenharmony_ci error = sysc_enable_opt_clocks(ddata); 21478c2ecf20Sopenharmony_ci if (error) 21488c2ecf20Sopenharmony_ci return error; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci error = sysc_enable_main_clocks(ddata); 21518c2ecf20Sopenharmony_ci if (error) 21528c2ecf20Sopenharmony_ci goto err_opt_clocks; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) { 21558c2ecf20Sopenharmony_ci error = reset_control_deassert(ddata->rsts); 21568c2ecf20Sopenharmony_ci if (error) 21578c2ecf20Sopenharmony_ci goto err_main_clocks; 21588c2ecf20Sopenharmony_ci } 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci ddata->revision = sysc_read_revision(ddata); 21618c2ecf20Sopenharmony_ci sysc_init_revision_quirks(ddata); 21628c2ecf20Sopenharmony_ci sysc_init_module_quirks(ddata); 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (ddata->legacy_mode) { 21658c2ecf20Sopenharmony_ci error = sysc_legacy_init(ddata); 21668c2ecf20Sopenharmony_ci if (error) 21678c2ecf20Sopenharmony_ci goto err_reset; 21688c2ecf20Sopenharmony_ci } 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci if (!ddata->legacy_mode) { 21718c2ecf20Sopenharmony_ci error = sysc_enable_module(ddata->dev); 21728c2ecf20Sopenharmony_ci if (error) 21738c2ecf20Sopenharmony_ci goto err_reset; 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci error = sysc_reset(ddata); 21778c2ecf20Sopenharmony_ci if (error) 21788c2ecf20Sopenharmony_ci dev_err(ddata->dev, "Reset failed with %d\n", error); 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci if (error && !ddata->legacy_mode) 21818c2ecf20Sopenharmony_ci sysc_disable_module(ddata->dev); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_cierr_reset: 21848c2ecf20Sopenharmony_ci if (error && !(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) 21858c2ecf20Sopenharmony_ci reset_control_assert(ddata->rsts); 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_cierr_main_clocks: 21888c2ecf20Sopenharmony_ci if (error) 21898c2ecf20Sopenharmony_ci sysc_disable_main_clocks(ddata); 21908c2ecf20Sopenharmony_cierr_opt_clocks: 21918c2ecf20Sopenharmony_ci /* No re-enable of clockdomain autoidle to prevent module autoidle */ 21928c2ecf20Sopenharmony_ci if (error) { 21938c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 21948c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 21958c2ecf20Sopenharmony_ci } 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci return error; 21988c2ecf20Sopenharmony_ci} 21998c2ecf20Sopenharmony_ci 22008c2ecf20Sopenharmony_cistatic int sysc_init_sysc_mask(struct sysc *ddata) 22018c2ecf20Sopenharmony_ci{ 22028c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 22038c2ecf20Sopenharmony_ci int error; 22048c2ecf20Sopenharmony_ci u32 val; 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci error = of_property_read_u32(np, "ti,sysc-mask", &val); 22078c2ecf20Sopenharmony_ci if (error) 22088c2ecf20Sopenharmony_ci return 0; 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci ddata->cfg.sysc_val = val & ddata->cap->sysc_mask; 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci return 0; 22138c2ecf20Sopenharmony_ci} 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_cistatic int sysc_init_idlemode(struct sysc *ddata, u8 *idlemodes, 22168c2ecf20Sopenharmony_ci const char *name) 22178c2ecf20Sopenharmony_ci{ 22188c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 22198c2ecf20Sopenharmony_ci struct property *prop; 22208c2ecf20Sopenharmony_ci const __be32 *p; 22218c2ecf20Sopenharmony_ci u32 val; 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci of_property_for_each_u32(np, name, prop, p, val) { 22248c2ecf20Sopenharmony_ci if (val >= SYSC_NR_IDLEMODES) { 22258c2ecf20Sopenharmony_ci dev_err(ddata->dev, "invalid idlemode: %i\n", val); 22268c2ecf20Sopenharmony_ci return -EINVAL; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci *idlemodes |= (1 << val); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci 22318c2ecf20Sopenharmony_ci return 0; 22328c2ecf20Sopenharmony_ci} 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic int sysc_init_idlemodes(struct sysc *ddata) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci int error; 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci error = sysc_init_idlemode(ddata, &ddata->cfg.midlemodes, 22398c2ecf20Sopenharmony_ci "ti,sysc-midle"); 22408c2ecf20Sopenharmony_ci if (error) 22418c2ecf20Sopenharmony_ci return error; 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci error = sysc_init_idlemode(ddata, &ddata->cfg.sidlemodes, 22448c2ecf20Sopenharmony_ci "ti,sysc-sidle"); 22458c2ecf20Sopenharmony_ci if (error) 22468c2ecf20Sopenharmony_ci return error; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci return 0; 22498c2ecf20Sopenharmony_ci} 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci/* 22528c2ecf20Sopenharmony_ci * Only some devices on omap4 and later have SYSCONFIG reset done 22538c2ecf20Sopenharmony_ci * bit. We can detect this if there is no SYSSTATUS at all, or the 22548c2ecf20Sopenharmony_ci * SYSTATUS bit 0 is not used. Note that some SYSSTATUS registers 22558c2ecf20Sopenharmony_ci * have multiple bits for the child devices like OHCI and EHCI. 22568c2ecf20Sopenharmony_ci * Depends on SYSC being parsed first. 22578c2ecf20Sopenharmony_ci */ 22588c2ecf20Sopenharmony_cistatic int sysc_init_syss_mask(struct sysc *ddata) 22598c2ecf20Sopenharmony_ci{ 22608c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 22618c2ecf20Sopenharmony_ci int error; 22628c2ecf20Sopenharmony_ci u32 val; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci error = of_property_read_u32(np, "ti,syss-mask", &val); 22658c2ecf20Sopenharmony_ci if (error) { 22668c2ecf20Sopenharmony_ci if ((ddata->cap->type == TI_SYSC_OMAP4 || 22678c2ecf20Sopenharmony_ci ddata->cap->type == TI_SYSC_OMAP4_TIMER) && 22688c2ecf20Sopenharmony_ci (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) 22698c2ecf20Sopenharmony_ci ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci return 0; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci if (!(val & 1) && (ddata->cfg.sysc_val & SYSC_OMAP4_SOFTRESET)) 22758c2ecf20Sopenharmony_ci ddata->cfg.quirks |= SYSC_QUIRK_RESET_STATUS; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_ci ddata->cfg.syss_mask = val; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci return 0; 22808c2ecf20Sopenharmony_ci} 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci/* 22838c2ecf20Sopenharmony_ci * Many child device drivers need to have fck and opt clocks available 22848c2ecf20Sopenharmony_ci * to get the clock rate for device internal configuration etc. 22858c2ecf20Sopenharmony_ci */ 22868c2ecf20Sopenharmony_cistatic int sysc_child_add_named_clock(struct sysc *ddata, 22878c2ecf20Sopenharmony_ci struct device *child, 22888c2ecf20Sopenharmony_ci const char *name) 22898c2ecf20Sopenharmony_ci{ 22908c2ecf20Sopenharmony_ci struct clk *clk; 22918c2ecf20Sopenharmony_ci struct clk_lookup *l; 22928c2ecf20Sopenharmony_ci int error = 0; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (!name) 22958c2ecf20Sopenharmony_ci return 0; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci clk = clk_get(child, name); 22988c2ecf20Sopenharmony_ci if (!IS_ERR(clk)) { 22998c2ecf20Sopenharmony_ci error = -EEXIST; 23008c2ecf20Sopenharmony_ci goto put_clk; 23018c2ecf20Sopenharmony_ci } 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci clk = clk_get(ddata->dev, name); 23048c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 23058c2ecf20Sopenharmony_ci return -ENODEV; 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci l = clkdev_create(clk, name, dev_name(child)); 23088c2ecf20Sopenharmony_ci if (!l) 23098c2ecf20Sopenharmony_ci error = -ENOMEM; 23108c2ecf20Sopenharmony_ciput_clk: 23118c2ecf20Sopenharmony_ci clk_put(clk); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ci return error; 23148c2ecf20Sopenharmony_ci} 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_cistatic int sysc_child_add_clocks(struct sysc *ddata, 23178c2ecf20Sopenharmony_ci struct device *child) 23188c2ecf20Sopenharmony_ci{ 23198c2ecf20Sopenharmony_ci int i, error; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci for (i = 0; i < ddata->nr_clocks; i++) { 23228c2ecf20Sopenharmony_ci error = sysc_child_add_named_clock(ddata, 23238c2ecf20Sopenharmony_ci child, 23248c2ecf20Sopenharmony_ci ddata->clock_roles[i]); 23258c2ecf20Sopenharmony_ci if (error && error != -EEXIST) { 23268c2ecf20Sopenharmony_ci dev_err(ddata->dev, "could not add child clock %s: %i\n", 23278c2ecf20Sopenharmony_ci ddata->clock_roles[i], error); 23288c2ecf20Sopenharmony_ci 23298c2ecf20Sopenharmony_ci return error; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci return 0; 23348c2ecf20Sopenharmony_ci} 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_cistatic struct device_type sysc_device_type = { 23378c2ecf20Sopenharmony_ci}; 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_cistatic struct sysc *sysc_child_to_parent(struct device *dev) 23408c2ecf20Sopenharmony_ci{ 23418c2ecf20Sopenharmony_ci struct device *parent = dev->parent; 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci if (!parent || parent->type != &sysc_device_type) 23448c2ecf20Sopenharmony_ci return NULL; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci return dev_get_drvdata(parent); 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_child_runtime_suspend(struct device *dev) 23508c2ecf20Sopenharmony_ci{ 23518c2ecf20Sopenharmony_ci struct sysc *ddata; 23528c2ecf20Sopenharmony_ci int error; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci ddata = sysc_child_to_parent(dev); 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci error = pm_generic_runtime_suspend(dev); 23578c2ecf20Sopenharmony_ci if (error) 23588c2ecf20Sopenharmony_ci return error; 23598c2ecf20Sopenharmony_ci 23608c2ecf20Sopenharmony_ci if (!ddata->enabled) 23618c2ecf20Sopenharmony_ci return 0; 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_ci return sysc_runtime_suspend(ddata->dev); 23648c2ecf20Sopenharmony_ci} 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_cistatic int __maybe_unused sysc_child_runtime_resume(struct device *dev) 23678c2ecf20Sopenharmony_ci{ 23688c2ecf20Sopenharmony_ci struct sysc *ddata; 23698c2ecf20Sopenharmony_ci int error; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci ddata = sysc_child_to_parent(dev); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci if (!ddata->enabled) { 23748c2ecf20Sopenharmony_ci error = sysc_runtime_resume(ddata->dev); 23758c2ecf20Sopenharmony_ci if (error < 0) 23768c2ecf20Sopenharmony_ci dev_err(ddata->dev, 23778c2ecf20Sopenharmony_ci "%s error: %i\n", __func__, error); 23788c2ecf20Sopenharmony_ci } 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci return pm_generic_runtime_resume(dev); 23818c2ecf20Sopenharmony_ci} 23828c2ecf20Sopenharmony_ci 23838c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23848c2ecf20Sopenharmony_cistatic int sysc_child_suspend_noirq(struct device *dev) 23858c2ecf20Sopenharmony_ci{ 23868c2ecf20Sopenharmony_ci struct sysc *ddata; 23878c2ecf20Sopenharmony_ci int error; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci ddata = sysc_child_to_parent(dev); 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci dev_dbg(ddata->dev, "%s %s\n", __func__, 23928c2ecf20Sopenharmony_ci ddata->name ? ddata->name : ""); 23938c2ecf20Sopenharmony_ci 23948c2ecf20Sopenharmony_ci error = pm_generic_suspend_noirq(dev); 23958c2ecf20Sopenharmony_ci if (error) { 23968c2ecf20Sopenharmony_ci dev_err(dev, "%s error at %i: %i\n", 23978c2ecf20Sopenharmony_ci __func__, __LINE__, error); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return error; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(dev)) { 24038c2ecf20Sopenharmony_ci error = pm_generic_runtime_suspend(dev); 24048c2ecf20Sopenharmony_ci if (error) { 24058c2ecf20Sopenharmony_ci dev_dbg(dev, "%s busy at %i: %i\n", 24068c2ecf20Sopenharmony_ci __func__, __LINE__, error); 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_ci return 0; 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci error = sysc_runtime_suspend(ddata->dev); 24128c2ecf20Sopenharmony_ci if (error) { 24138c2ecf20Sopenharmony_ci dev_err(dev, "%s error at %i: %i\n", 24148c2ecf20Sopenharmony_ci __func__, __LINE__, error); 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci return error; 24178c2ecf20Sopenharmony_ci } 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci ddata->child_needs_resume = true; 24208c2ecf20Sopenharmony_ci } 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci return 0; 24238c2ecf20Sopenharmony_ci} 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_cistatic int sysc_child_resume_noirq(struct device *dev) 24268c2ecf20Sopenharmony_ci{ 24278c2ecf20Sopenharmony_ci struct sysc *ddata; 24288c2ecf20Sopenharmony_ci int error; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci ddata = sysc_child_to_parent(dev); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci dev_dbg(ddata->dev, "%s %s\n", __func__, 24338c2ecf20Sopenharmony_ci ddata->name ? ddata->name : ""); 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci if (ddata->child_needs_resume) { 24368c2ecf20Sopenharmony_ci ddata->child_needs_resume = false; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_ci error = sysc_runtime_resume(ddata->dev); 24398c2ecf20Sopenharmony_ci if (error) 24408c2ecf20Sopenharmony_ci dev_err(ddata->dev, 24418c2ecf20Sopenharmony_ci "%s runtime resume error: %i\n", 24428c2ecf20Sopenharmony_ci __func__, error); 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci error = pm_generic_runtime_resume(dev); 24458c2ecf20Sopenharmony_ci if (error) 24468c2ecf20Sopenharmony_ci dev_err(ddata->dev, 24478c2ecf20Sopenharmony_ci "%s generic runtime resume: %i\n", 24488c2ecf20Sopenharmony_ci __func__, error); 24498c2ecf20Sopenharmony_ci } 24508c2ecf20Sopenharmony_ci 24518c2ecf20Sopenharmony_ci return pm_generic_resume_noirq(dev); 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci#endif 24548c2ecf20Sopenharmony_ci 24558c2ecf20Sopenharmony_cistatic struct dev_pm_domain sysc_child_pm_domain = { 24568c2ecf20Sopenharmony_ci .ops = { 24578c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(sysc_child_runtime_suspend, 24588c2ecf20Sopenharmony_ci sysc_child_runtime_resume, 24598c2ecf20Sopenharmony_ci NULL) 24608c2ecf20Sopenharmony_ci USE_PLATFORM_PM_SLEEP_OPS 24618c2ecf20Sopenharmony_ci SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_child_suspend_noirq, 24628c2ecf20Sopenharmony_ci sysc_child_resume_noirq) 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci}; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci/* Caller needs to take list_lock if ever used outside of cpu_pm */ 24678c2ecf20Sopenharmony_cistatic void sysc_reinit_modules(struct sysc_soc_info *soc) 24688c2ecf20Sopenharmony_ci{ 24698c2ecf20Sopenharmony_ci struct sysc_module *module; 24708c2ecf20Sopenharmony_ci struct list_head *pos; 24718c2ecf20Sopenharmony_ci struct sysc *ddata; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci list_for_each(pos, &sysc_soc->restored_modules) { 24748c2ecf20Sopenharmony_ci module = list_entry(pos, struct sysc_module, node); 24758c2ecf20Sopenharmony_ci ddata = module->ddata; 24768c2ecf20Sopenharmony_ci sysc_reinit_module(ddata, ddata->enabled); 24778c2ecf20Sopenharmony_ci } 24788c2ecf20Sopenharmony_ci} 24798c2ecf20Sopenharmony_ci 24808c2ecf20Sopenharmony_ci/** 24818c2ecf20Sopenharmony_ci * sysc_context_notifier - optionally reset and restore module after idle 24828c2ecf20Sopenharmony_ci * @nb: notifier block 24838c2ecf20Sopenharmony_ci * @cmd: unused 24848c2ecf20Sopenharmony_ci * @v: unused 24858c2ecf20Sopenharmony_ci * 24868c2ecf20Sopenharmony_ci * Some interconnect target modules need to be restored, or reset and restored 24878c2ecf20Sopenharmony_ci * on CPU_PM CPU_PM_CLUSTER_EXIT notifier. This is needed at least for am335x 24888c2ecf20Sopenharmony_ci * OTG and GPMC target modules even if the modules are unused. 24898c2ecf20Sopenharmony_ci */ 24908c2ecf20Sopenharmony_cistatic int sysc_context_notifier(struct notifier_block *nb, unsigned long cmd, 24918c2ecf20Sopenharmony_ci void *v) 24928c2ecf20Sopenharmony_ci{ 24938c2ecf20Sopenharmony_ci struct sysc_soc_info *soc; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci soc = container_of(nb, struct sysc_soc_info, nb); 24968c2ecf20Sopenharmony_ci 24978c2ecf20Sopenharmony_ci switch (cmd) { 24988c2ecf20Sopenharmony_ci case CPU_CLUSTER_PM_ENTER: 24998c2ecf20Sopenharmony_ci break; 25008c2ecf20Sopenharmony_ci case CPU_CLUSTER_PM_ENTER_FAILED: /* No need to restore context */ 25018c2ecf20Sopenharmony_ci break; 25028c2ecf20Sopenharmony_ci case CPU_CLUSTER_PM_EXIT: 25038c2ecf20Sopenharmony_ci sysc_reinit_modules(soc); 25048c2ecf20Sopenharmony_ci break; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci return NOTIFY_OK; 25088c2ecf20Sopenharmony_ci} 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ci/** 25118c2ecf20Sopenharmony_ci * sysc_add_restored - optionally add reset and restore quirk hanlling 25128c2ecf20Sopenharmony_ci * @ddata: device data 25138c2ecf20Sopenharmony_ci */ 25148c2ecf20Sopenharmony_cistatic void sysc_add_restored(struct sysc *ddata) 25158c2ecf20Sopenharmony_ci{ 25168c2ecf20Sopenharmony_ci struct sysc_module *restored_module; 25178c2ecf20Sopenharmony_ci 25188c2ecf20Sopenharmony_ci restored_module = kzalloc(sizeof(*restored_module), GFP_KERNEL); 25198c2ecf20Sopenharmony_ci if (!restored_module) 25208c2ecf20Sopenharmony_ci return; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci restored_module->ddata = ddata; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci mutex_lock(&sysc_soc->list_lock); 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci list_add(&restored_module->node, &sysc_soc->restored_modules); 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (sysc_soc->nb.notifier_call) 25298c2ecf20Sopenharmony_ci goto out_unlock; 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci sysc_soc->nb.notifier_call = sysc_context_notifier; 25328c2ecf20Sopenharmony_ci cpu_pm_register_notifier(&sysc_soc->nb); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ciout_unlock: 25358c2ecf20Sopenharmony_ci mutex_unlock(&sysc_soc->list_lock); 25368c2ecf20Sopenharmony_ci} 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci/** 25398c2ecf20Sopenharmony_ci * sysc_legacy_idle_quirk - handle children in omap_device compatible way 25408c2ecf20Sopenharmony_ci * @ddata: device driver data 25418c2ecf20Sopenharmony_ci * @child: child device driver 25428c2ecf20Sopenharmony_ci * 25438c2ecf20Sopenharmony_ci * Allow idle for child devices as done with _od_runtime_suspend(). 25448c2ecf20Sopenharmony_ci * Otherwise many child devices will not idle because of the permanent 25458c2ecf20Sopenharmony_ci * parent usecount set in pm_runtime_irq_safe(). 25468c2ecf20Sopenharmony_ci * 25478c2ecf20Sopenharmony_ci * Note that the long term solution is to just modify the child device 25488c2ecf20Sopenharmony_ci * drivers to not set pm_runtime_irq_safe() and then this can be just 25498c2ecf20Sopenharmony_ci * dropped. 25508c2ecf20Sopenharmony_ci */ 25518c2ecf20Sopenharmony_cistatic void sysc_legacy_idle_quirk(struct sysc *ddata, struct device *child) 25528c2ecf20Sopenharmony_ci{ 25538c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) 25548c2ecf20Sopenharmony_ci dev_pm_domain_set(child, &sysc_child_pm_domain); 25558c2ecf20Sopenharmony_ci} 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_cistatic int sysc_notifier_call(struct notifier_block *nb, 25588c2ecf20Sopenharmony_ci unsigned long event, void *device) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci struct device *dev = device; 25618c2ecf20Sopenharmony_ci struct sysc *ddata; 25628c2ecf20Sopenharmony_ci int error; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci ddata = sysc_child_to_parent(dev); 25658c2ecf20Sopenharmony_ci if (!ddata) 25668c2ecf20Sopenharmony_ci return NOTIFY_DONE; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci switch (event) { 25698c2ecf20Sopenharmony_ci case BUS_NOTIFY_ADD_DEVICE: 25708c2ecf20Sopenharmony_ci error = sysc_child_add_clocks(ddata, dev); 25718c2ecf20Sopenharmony_ci if (error) 25728c2ecf20Sopenharmony_ci return error; 25738c2ecf20Sopenharmony_ci sysc_legacy_idle_quirk(ddata, dev); 25748c2ecf20Sopenharmony_ci break; 25758c2ecf20Sopenharmony_ci default: 25768c2ecf20Sopenharmony_ci break; 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci return NOTIFY_DONE; 25808c2ecf20Sopenharmony_ci} 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_cistatic struct notifier_block sysc_nb = { 25838c2ecf20Sopenharmony_ci .notifier_call = sysc_notifier_call, 25848c2ecf20Sopenharmony_ci}; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_ci/* Device tree configured quirks */ 25878c2ecf20Sopenharmony_cistruct sysc_dts_quirk { 25888c2ecf20Sopenharmony_ci const char *name; 25898c2ecf20Sopenharmony_ci u32 mask; 25908c2ecf20Sopenharmony_ci}; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_cistatic const struct sysc_dts_quirk sysc_dts_quirks[] = { 25938c2ecf20Sopenharmony_ci { .name = "ti,no-idle-on-init", 25948c2ecf20Sopenharmony_ci .mask = SYSC_QUIRK_NO_IDLE_ON_INIT, }, 25958c2ecf20Sopenharmony_ci { .name = "ti,no-reset-on-init", 25968c2ecf20Sopenharmony_ci .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, 25978c2ecf20Sopenharmony_ci { .name = "ti,no-idle", 25988c2ecf20Sopenharmony_ci .mask = SYSC_QUIRK_NO_IDLE, }, 25998c2ecf20Sopenharmony_ci}; 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_cistatic void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, 26028c2ecf20Sopenharmony_ci bool is_child) 26038c2ecf20Sopenharmony_ci{ 26048c2ecf20Sopenharmony_ci const struct property *prop; 26058c2ecf20Sopenharmony_ci int i, len; 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { 26088c2ecf20Sopenharmony_ci const char *name = sysc_dts_quirks[i].name; 26098c2ecf20Sopenharmony_ci 26108c2ecf20Sopenharmony_ci prop = of_get_property(np, name, &len); 26118c2ecf20Sopenharmony_ci if (!prop) 26128c2ecf20Sopenharmony_ci continue; 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci ddata->cfg.quirks |= sysc_dts_quirks[i].mask; 26158c2ecf20Sopenharmony_ci if (is_child) { 26168c2ecf20Sopenharmony_ci dev_warn(ddata->dev, 26178c2ecf20Sopenharmony_ci "dts flag should be at module level for %s\n", 26188c2ecf20Sopenharmony_ci name); 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci } 26218c2ecf20Sopenharmony_ci} 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_cistatic int sysc_init_dts_quirks(struct sysc *ddata) 26248c2ecf20Sopenharmony_ci{ 26258c2ecf20Sopenharmony_ci struct device_node *np = ddata->dev->of_node; 26268c2ecf20Sopenharmony_ci int error; 26278c2ecf20Sopenharmony_ci u32 val; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci sysc_parse_dts_quirks(ddata, np, false); 26328c2ecf20Sopenharmony_ci error = of_property_read_u32(np, "ti,sysc-delay-us", &val); 26338c2ecf20Sopenharmony_ci if (!error) { 26348c2ecf20Sopenharmony_ci if (val > 255) { 26358c2ecf20Sopenharmony_ci dev_warn(ddata->dev, "bad ti,sysc-delay-us: %i\n", 26368c2ecf20Sopenharmony_ci val); 26378c2ecf20Sopenharmony_ci } 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ci ddata->cfg.srst_udelay = (u8)val; 26408c2ecf20Sopenharmony_ci } 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci return 0; 26438c2ecf20Sopenharmony_ci} 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_cistatic void sysc_unprepare(struct sysc *ddata) 26468c2ecf20Sopenharmony_ci{ 26478c2ecf20Sopenharmony_ci int i; 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci if (!ddata->clocks) 26508c2ecf20Sopenharmony_ci return; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci for (i = 0; i < SYSC_MAX_CLOCKS; i++) { 26538c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(ddata->clocks[i])) 26548c2ecf20Sopenharmony_ci clk_unprepare(ddata->clocks[i]); 26558c2ecf20Sopenharmony_ci } 26568c2ecf20Sopenharmony_ci} 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci/* 26598c2ecf20Sopenharmony_ci * Common sysc register bits found on omap2, also known as type1 26608c2ecf20Sopenharmony_ci */ 26618c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap2 = { 26628c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 26638c2ecf20Sopenharmony_ci .midle_shift = 12, 26648c2ecf20Sopenharmony_ci .sidle_shift = 3, 26658c2ecf20Sopenharmony_ci .clkact_shift = 8, 26668c2ecf20Sopenharmony_ci .emufree_shift = 5, 26678c2ecf20Sopenharmony_ci .enwkup_shift = 2, 26688c2ecf20Sopenharmony_ci .srst_shift = 1, 26698c2ecf20Sopenharmony_ci .autoidle_shift = 0, 26708c2ecf20Sopenharmony_ci}; 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap2 = { 26738c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP2, 26748c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE | 26758c2ecf20Sopenharmony_ci SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET | 26768c2ecf20Sopenharmony_ci SYSC_OMAP2_AUTOIDLE, 26778c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap2, 26788c2ecf20Sopenharmony_ci}; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci/* All omap2 and 3 timers, and timers 1, 2 & 10 on omap 4 and 5 */ 26818c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap2_timer = { 26828c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP2_TIMER, 26838c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY | SYSC_OMAP2_EMUFREE | 26848c2ecf20Sopenharmony_ci SYSC_OMAP2_ENAWAKEUP | SYSC_OMAP2_SOFTRESET | 26858c2ecf20Sopenharmony_ci SYSC_OMAP2_AUTOIDLE, 26868c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap2, 26878c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_USE_CLOCKACT, 26888c2ecf20Sopenharmony_ci}; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci/* 26918c2ecf20Sopenharmony_ci * SHAM2 (SHA1/MD5) sysc found on omap3, a variant of sysc_regbits_omap2 26928c2ecf20Sopenharmony_ci * with different sidle position 26938c2ecf20Sopenharmony_ci */ 26948c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap3_sham = { 26958c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 26968c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 26978c2ecf20Sopenharmony_ci .sidle_shift = 4, 26988c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 26998c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 27008c2ecf20Sopenharmony_ci .srst_shift = 1, 27018c2ecf20Sopenharmony_ci .autoidle_shift = 0, 27028c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 27038c2ecf20Sopenharmony_ci}; 27048c2ecf20Sopenharmony_ci 27058c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap3_sham = { 27068c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP3_SHAM, 27078c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE, 27088c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap3_sham, 27098c2ecf20Sopenharmony_ci}; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci/* 27128c2ecf20Sopenharmony_ci * AES register bits found on omap3 and later, a variant of 27138c2ecf20Sopenharmony_ci * sysc_regbits_omap2 with different sidle position 27148c2ecf20Sopenharmony_ci */ 27158c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap3_aes = { 27168c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 27178c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 27188c2ecf20Sopenharmony_ci .sidle_shift = 6, 27198c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 27208c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 27218c2ecf20Sopenharmony_ci .srst_shift = 1, 27228c2ecf20Sopenharmony_ci .autoidle_shift = 0, 27238c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 27248c2ecf20Sopenharmony_ci}; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap3_aes = { 27278c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP3_AES, 27288c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_SOFTRESET | SYSC_OMAP2_AUTOIDLE, 27298c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap3_aes, 27308c2ecf20Sopenharmony_ci}; 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci/* 27338c2ecf20Sopenharmony_ci * Common sysc register bits found on omap4, also known as type2 27348c2ecf20Sopenharmony_ci */ 27358c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap4 = { 27368c2ecf20Sopenharmony_ci .dmadisable_shift = 16, 27378c2ecf20Sopenharmony_ci .midle_shift = 4, 27388c2ecf20Sopenharmony_ci .sidle_shift = 2, 27398c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 27408c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 27418c2ecf20Sopenharmony_ci .emufree_shift = 1, 27428c2ecf20Sopenharmony_ci .srst_shift = 0, 27438c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 27448c2ecf20Sopenharmony_ci}; 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4 = { 27478c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4, 27488c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU | 27498c2ecf20Sopenharmony_ci SYSC_OMAP4_SOFTRESET, 27508c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4, 27518c2ecf20Sopenharmony_ci}; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4_timer = { 27548c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_TIMER, 27558c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP4_DMADISABLE | SYSC_OMAP4_FREEEMU | 27568c2ecf20Sopenharmony_ci SYSC_OMAP4_SOFTRESET, 27578c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4, 27588c2ecf20Sopenharmony_ci}; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci/* 27618c2ecf20Sopenharmony_ci * Common sysc register bits found on omap4, also known as type3 27628c2ecf20Sopenharmony_ci */ 27638c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap4_simple = { 27648c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 27658c2ecf20Sopenharmony_ci .midle_shift = 2, 27668c2ecf20Sopenharmony_ci .sidle_shift = 0, 27678c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 27688c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 27698c2ecf20Sopenharmony_ci .srst_shift = -ENODEV, 27708c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 27718c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 27728c2ecf20Sopenharmony_ci}; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4_simple = { 27758c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_SIMPLE, 27768c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4_simple, 27778c2ecf20Sopenharmony_ci}; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci/* 27808c2ecf20Sopenharmony_ci * SmartReflex sysc found on omap34xx 27818c2ecf20Sopenharmony_ci */ 27828c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap34xx_sr = { 27838c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 27848c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 27858c2ecf20Sopenharmony_ci .sidle_shift = -ENODEV, 27868c2ecf20Sopenharmony_ci .clkact_shift = 20, 27878c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 27888c2ecf20Sopenharmony_ci .srst_shift = -ENODEV, 27898c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 27908c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 27918c2ecf20Sopenharmony_ci}; 27928c2ecf20Sopenharmony_ci 27938c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_34xx_sr = { 27948c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP34XX_SR, 27958c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_CLOCKACTIVITY, 27968c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap34xx_sr, 27978c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_USE_CLOCKACT | SYSC_QUIRK_UNCACHED | 27988c2ecf20Sopenharmony_ci SYSC_QUIRK_LEGACY_IDLE, 27998c2ecf20Sopenharmony_ci}; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci/* 28028c2ecf20Sopenharmony_ci * SmartReflex sysc found on omap36xx and later 28038c2ecf20Sopenharmony_ci */ 28048c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap36xx_sr = { 28058c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 28068c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 28078c2ecf20Sopenharmony_ci .sidle_shift = 24, 28088c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 28098c2ecf20Sopenharmony_ci .enwkup_shift = 26, 28108c2ecf20Sopenharmony_ci .srst_shift = -ENODEV, 28118c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 28128c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 28138c2ecf20Sopenharmony_ci}; 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_36xx_sr = { 28168c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP36XX_SR, 28178c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP3_SR_ENAWAKEUP, 28188c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap36xx_sr, 28198c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_UNCACHED | SYSC_QUIRK_LEGACY_IDLE, 28208c2ecf20Sopenharmony_ci}; 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4_sr = { 28238c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_SR, 28248c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap36xx_sr, 28258c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_LEGACY_IDLE, 28268c2ecf20Sopenharmony_ci}; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci/* 28298c2ecf20Sopenharmony_ci * McASP register bits found on omap4 and later 28308c2ecf20Sopenharmony_ci */ 28318c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap4_mcasp = { 28328c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 28338c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 28348c2ecf20Sopenharmony_ci .sidle_shift = 0, 28358c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 28368c2ecf20Sopenharmony_ci .enwkup_shift = -ENODEV, 28378c2ecf20Sopenharmony_ci .srst_shift = -ENODEV, 28388c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 28398c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 28408c2ecf20Sopenharmony_ci}; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4_mcasp = { 28438c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_MCASP, 28448c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4_mcasp, 28458c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, 28468c2ecf20Sopenharmony_ci}; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci/* 28498c2ecf20Sopenharmony_ci * McASP found on dra7 and later 28508c2ecf20Sopenharmony_ci */ 28518c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_dra7_mcasp = { 28528c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_SIMPLE, 28538c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4_simple, 28548c2ecf20Sopenharmony_ci .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, 28558c2ecf20Sopenharmony_ci}; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci/* 28588c2ecf20Sopenharmony_ci * FS USB host found on omap4 and later 28598c2ecf20Sopenharmony_ci */ 28608c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_omap4_usb_host_fs = { 28618c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 28628c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 28638c2ecf20Sopenharmony_ci .sidle_shift = 24, 28648c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 28658c2ecf20Sopenharmony_ci .enwkup_shift = 26, 28668c2ecf20Sopenharmony_ci .srst_shift = -ENODEV, 28678c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 28688c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 28698c2ecf20Sopenharmony_ci}; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_omap4_usb_host_fs = { 28728c2ecf20Sopenharmony_ci .type = TI_SYSC_OMAP4_USB_HOST_FS, 28738c2ecf20Sopenharmony_ci .sysc_mask = SYSC_OMAP2_ENAWAKEUP, 28748c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4_usb_host_fs, 28758c2ecf20Sopenharmony_ci}; 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_cistatic const struct sysc_regbits sysc_regbits_dra7_mcan = { 28788c2ecf20Sopenharmony_ci .dmadisable_shift = -ENODEV, 28798c2ecf20Sopenharmony_ci .midle_shift = -ENODEV, 28808c2ecf20Sopenharmony_ci .sidle_shift = -ENODEV, 28818c2ecf20Sopenharmony_ci .clkact_shift = -ENODEV, 28828c2ecf20Sopenharmony_ci .enwkup_shift = 4, 28838c2ecf20Sopenharmony_ci .srst_shift = 0, 28848c2ecf20Sopenharmony_ci .emufree_shift = -ENODEV, 28858c2ecf20Sopenharmony_ci .autoidle_shift = -ENODEV, 28868c2ecf20Sopenharmony_ci}; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_dra7_mcan = { 28898c2ecf20Sopenharmony_ci .type = TI_SYSC_DRA7_MCAN, 28908c2ecf20Sopenharmony_ci .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET, 28918c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_dra7_mcan, 28928c2ecf20Sopenharmony_ci .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED, 28938c2ecf20Sopenharmony_ci}; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci/* 28968c2ecf20Sopenharmony_ci * PRUSS found on some AM33xx, AM437x and AM57xx SoCs 28978c2ecf20Sopenharmony_ci */ 28988c2ecf20Sopenharmony_cistatic const struct sysc_capabilities sysc_pruss = { 28998c2ecf20Sopenharmony_ci .type = TI_SYSC_PRUSS, 29008c2ecf20Sopenharmony_ci .sysc_mask = SYSC_PRUSS_STANDBY_INIT | SYSC_PRUSS_SUB_MWAIT, 29018c2ecf20Sopenharmony_ci .regbits = &sysc_regbits_omap4_simple, 29028c2ecf20Sopenharmony_ci .mod_quirks = SYSC_MODULE_QUIRK_PRUSS, 29038c2ecf20Sopenharmony_ci}; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_cistatic int sysc_init_pdata(struct sysc *ddata) 29068c2ecf20Sopenharmony_ci{ 29078c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); 29088c2ecf20Sopenharmony_ci struct ti_sysc_module_data *mdata; 29098c2ecf20Sopenharmony_ci 29108c2ecf20Sopenharmony_ci if (!pdata) 29118c2ecf20Sopenharmony_ci return 0; 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci mdata = devm_kzalloc(ddata->dev, sizeof(*mdata), GFP_KERNEL); 29148c2ecf20Sopenharmony_ci if (!mdata) 29158c2ecf20Sopenharmony_ci return -ENOMEM; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci if (ddata->legacy_mode) { 29188c2ecf20Sopenharmony_ci mdata->name = ddata->legacy_mode; 29198c2ecf20Sopenharmony_ci mdata->module_pa = ddata->module_pa; 29208c2ecf20Sopenharmony_ci mdata->module_size = ddata->module_size; 29218c2ecf20Sopenharmony_ci mdata->offsets = ddata->offsets; 29228c2ecf20Sopenharmony_ci mdata->nr_offsets = SYSC_MAX_REGS; 29238c2ecf20Sopenharmony_ci mdata->cap = ddata->cap; 29248c2ecf20Sopenharmony_ci mdata->cfg = &ddata->cfg; 29258c2ecf20Sopenharmony_ci } 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci ddata->mdata = mdata; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci return 0; 29308c2ecf20Sopenharmony_ci} 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_cistatic int sysc_init_match(struct sysc *ddata) 29338c2ecf20Sopenharmony_ci{ 29348c2ecf20Sopenharmony_ci const struct sysc_capabilities *cap; 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci cap = of_device_get_match_data(ddata->dev); 29378c2ecf20Sopenharmony_ci if (!cap) 29388c2ecf20Sopenharmony_ci return -EINVAL; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci ddata->cap = cap; 29418c2ecf20Sopenharmony_ci if (ddata->cap) 29428c2ecf20Sopenharmony_ci ddata->cfg.quirks |= ddata->cap->mod_quirks; 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci return 0; 29458c2ecf20Sopenharmony_ci} 29468c2ecf20Sopenharmony_ci 29478c2ecf20Sopenharmony_cistatic void ti_sysc_idle(struct work_struct *work) 29488c2ecf20Sopenharmony_ci{ 29498c2ecf20Sopenharmony_ci struct sysc *ddata; 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_ci ddata = container_of(work, struct sysc, idle_work.work); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci /* 29548c2ecf20Sopenharmony_ci * One time decrement of clock usage counts if left on from init. 29558c2ecf20Sopenharmony_ci * Note that we disable opt clocks unconditionally in this case 29568c2ecf20Sopenharmony_ci * as they are enabled unconditionally during init without 29578c2ecf20Sopenharmony_ci * considering sysc_opt_clks_needed() at that point. 29588c2ecf20Sopenharmony_ci */ 29598c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE | 29608c2ecf20Sopenharmony_ci SYSC_QUIRK_NO_IDLE_ON_INIT)) { 29618c2ecf20Sopenharmony_ci sysc_disable_main_clocks(ddata); 29628c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 29638c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 29648c2ecf20Sopenharmony_ci } 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_ci /* Keep permanent PM runtime usage count for SYSC_QUIRK_NO_IDLE */ 29678c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE) 29688c2ecf20Sopenharmony_ci return; 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci /* 29718c2ecf20Sopenharmony_ci * Decrement PM runtime usage count for SYSC_QUIRK_NO_IDLE_ON_INIT 29728c2ecf20Sopenharmony_ci * and SYSC_QUIRK_NO_RESET_ON_INIT 29738c2ecf20Sopenharmony_ci */ 29748c2ecf20Sopenharmony_ci if (pm_runtime_active(ddata->dev)) 29758c2ecf20Sopenharmony_ci pm_runtime_put_sync(ddata->dev); 29768c2ecf20Sopenharmony_ci} 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci/* 29798c2ecf20Sopenharmony_ci * SoC model and features detection. Only needed for SoCs that need 29808c2ecf20Sopenharmony_ci * special handling for quirks, no need to list others. 29818c2ecf20Sopenharmony_ci */ 29828c2ecf20Sopenharmony_cistatic const struct soc_device_attribute sysc_soc_match[] = { 29838c2ecf20Sopenharmony_ci SOC_FLAG("OMAP242*", SOC_2420), 29848c2ecf20Sopenharmony_ci SOC_FLAG("OMAP243*", SOC_2430), 29858c2ecf20Sopenharmony_ci SOC_FLAG("AM35*", SOC_AM35), 29868c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3[45]*", SOC_3430), 29878c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3[67]*", SOC_3630), 29888c2ecf20Sopenharmony_ci SOC_FLAG("OMAP443*", SOC_4430), 29898c2ecf20Sopenharmony_ci SOC_FLAG("OMAP446*", SOC_4460), 29908c2ecf20Sopenharmony_ci SOC_FLAG("OMAP447*", SOC_4470), 29918c2ecf20Sopenharmony_ci SOC_FLAG("OMAP54*", SOC_5430), 29928c2ecf20Sopenharmony_ci SOC_FLAG("AM433", SOC_AM3), 29938c2ecf20Sopenharmony_ci SOC_FLAG("AM43*", SOC_AM4), 29948c2ecf20Sopenharmony_ci SOC_FLAG("DRA7*", SOC_DRA7), 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci { /* sentinel */ }, 29978c2ecf20Sopenharmony_ci}; 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci/* 30008c2ecf20Sopenharmony_ci * List of SoCs variants with disabled features. By default we assume all 30018c2ecf20Sopenharmony_ci * devices in the device tree are available so no need to list those SoCs. 30028c2ecf20Sopenharmony_ci */ 30038c2ecf20Sopenharmony_cistatic const struct soc_device_attribute sysc_soc_feat_match[] = { 30048c2ecf20Sopenharmony_ci /* OMAP3430/3530 and AM3517 variants with some accelerators disabled */ 30058c2ecf20Sopenharmony_ci SOC_FLAG("AM3505", DIS_SGX), 30068c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3525", DIS_SGX), 30078c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3515", DIS_IVA | DIS_SGX), 30088c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3503", DIS_ISP | DIS_IVA | DIS_SGX), 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci /* OMAP3630/DM3730 variants with some accelerators disabled */ 30118c2ecf20Sopenharmony_ci SOC_FLAG("AM3703", DIS_IVA | DIS_SGX), 30128c2ecf20Sopenharmony_ci SOC_FLAG("DM3725", DIS_SGX), 30138c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3611", DIS_ISP | DIS_IVA | DIS_SGX), 30148c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3615/AM3715", DIS_IVA), 30158c2ecf20Sopenharmony_ci SOC_FLAG("OMAP3621", DIS_ISP), 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci { /* sentinel */ }, 30188c2ecf20Sopenharmony_ci}; 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_cistatic int sysc_add_disabled(unsigned long base) 30218c2ecf20Sopenharmony_ci{ 30228c2ecf20Sopenharmony_ci struct sysc_address *disabled_module; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci disabled_module = kzalloc(sizeof(*disabled_module), GFP_KERNEL); 30258c2ecf20Sopenharmony_ci if (!disabled_module) 30268c2ecf20Sopenharmony_ci return -ENOMEM; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci disabled_module->base = base; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci mutex_lock(&sysc_soc->list_lock); 30318c2ecf20Sopenharmony_ci list_add(&disabled_module->node, &sysc_soc->disabled_modules); 30328c2ecf20Sopenharmony_ci mutex_unlock(&sysc_soc->list_lock); 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci return 0; 30358c2ecf20Sopenharmony_ci} 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci/* 30388c2ecf20Sopenharmony_ci * One time init to detect the booted SoC, disable unavailable features 30398c2ecf20Sopenharmony_ci * and initialize list for optional cpu_pm notifier. 30408c2ecf20Sopenharmony_ci * 30418c2ecf20Sopenharmony_ci * Note that we initialize static data shared across all ti-sysc instances 30428c2ecf20Sopenharmony_ci * so ddata is only used for SoC type. This can be called from module_init 30438c2ecf20Sopenharmony_ci * once we no longer need to rely on platform data. 30448c2ecf20Sopenharmony_ci */ 30458c2ecf20Sopenharmony_cistatic int sysc_init_static_data(struct sysc *ddata) 30468c2ecf20Sopenharmony_ci{ 30478c2ecf20Sopenharmony_ci const struct soc_device_attribute *match; 30488c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata; 30498c2ecf20Sopenharmony_ci unsigned long features = 0; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci if (sysc_soc) 30528c2ecf20Sopenharmony_ci return 0; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci sysc_soc = kzalloc(sizeof(*sysc_soc), GFP_KERNEL); 30558c2ecf20Sopenharmony_ci if (!sysc_soc) 30568c2ecf20Sopenharmony_ci return -ENOMEM; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci mutex_init(&sysc_soc->list_lock); 30598c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sysc_soc->disabled_modules); 30608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sysc_soc->restored_modules); 30618c2ecf20Sopenharmony_ci sysc_soc->general_purpose = true; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci pdata = dev_get_platdata(ddata->dev); 30648c2ecf20Sopenharmony_ci if (pdata && pdata->soc_type_gp) 30658c2ecf20Sopenharmony_ci sysc_soc->general_purpose = pdata->soc_type_gp(); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci match = soc_device_match(sysc_soc_match); 30688c2ecf20Sopenharmony_ci if (match && match->data) 30698c2ecf20Sopenharmony_ci sysc_soc->soc = (enum sysc_soc)(uintptr_t)match->data; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci /* Ignore devices that are not available on HS and EMU SoCs */ 30728c2ecf20Sopenharmony_ci if (!sysc_soc->general_purpose) { 30738c2ecf20Sopenharmony_ci switch (sysc_soc->soc) { 30748c2ecf20Sopenharmony_ci case SOC_3430 ... SOC_3630: 30758c2ecf20Sopenharmony_ci sysc_add_disabled(0x48304000); /* timer12 */ 30768c2ecf20Sopenharmony_ci break; 30778c2ecf20Sopenharmony_ci case SOC_AM3: 30788c2ecf20Sopenharmony_ci sysc_add_disabled(0x48310000); /* rng */ 30798c2ecf20Sopenharmony_ci break; 30808c2ecf20Sopenharmony_ci default: 30818c2ecf20Sopenharmony_ci break; 30828c2ecf20Sopenharmony_ci }; 30838c2ecf20Sopenharmony_ci } 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci match = soc_device_match(sysc_soc_feat_match); 30868c2ecf20Sopenharmony_ci if (!match) 30878c2ecf20Sopenharmony_ci return 0; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci if (match->data) 30908c2ecf20Sopenharmony_ci features = (unsigned long)match->data; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci /* 30938c2ecf20Sopenharmony_ci * Add disabled devices to the list based on the module base. 30948c2ecf20Sopenharmony_ci * Note that this must be done before we attempt to access the 30958c2ecf20Sopenharmony_ci * device and have module revision checks working. 30968c2ecf20Sopenharmony_ci */ 30978c2ecf20Sopenharmony_ci if (features & DIS_ISP) 30988c2ecf20Sopenharmony_ci sysc_add_disabled(0x480bd400); 30998c2ecf20Sopenharmony_ci if (features & DIS_IVA) 31008c2ecf20Sopenharmony_ci sysc_add_disabled(0x5d000000); 31018c2ecf20Sopenharmony_ci if (features & DIS_SGX) 31028c2ecf20Sopenharmony_ci sysc_add_disabled(0x50000000); 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_ci return 0; 31058c2ecf20Sopenharmony_ci} 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_cistatic void sysc_cleanup_static_data(void) 31088c2ecf20Sopenharmony_ci{ 31098c2ecf20Sopenharmony_ci struct sysc_module *restored_module; 31108c2ecf20Sopenharmony_ci struct sysc_address *disabled_module; 31118c2ecf20Sopenharmony_ci struct list_head *pos, *tmp; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci if (!sysc_soc) 31148c2ecf20Sopenharmony_ci return; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci if (sysc_soc->nb.notifier_call) 31178c2ecf20Sopenharmony_ci cpu_pm_unregister_notifier(&sysc_soc->nb); 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci mutex_lock(&sysc_soc->list_lock); 31208c2ecf20Sopenharmony_ci list_for_each_safe(pos, tmp, &sysc_soc->restored_modules) { 31218c2ecf20Sopenharmony_ci restored_module = list_entry(pos, struct sysc_module, node); 31228c2ecf20Sopenharmony_ci list_del(pos); 31238c2ecf20Sopenharmony_ci kfree(restored_module); 31248c2ecf20Sopenharmony_ci } 31258c2ecf20Sopenharmony_ci list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) { 31268c2ecf20Sopenharmony_ci disabled_module = list_entry(pos, struct sysc_address, node); 31278c2ecf20Sopenharmony_ci list_del(pos); 31288c2ecf20Sopenharmony_ci kfree(disabled_module); 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci mutex_unlock(&sysc_soc->list_lock); 31318c2ecf20Sopenharmony_ci} 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_cistatic int sysc_check_disabled_devices(struct sysc *ddata) 31348c2ecf20Sopenharmony_ci{ 31358c2ecf20Sopenharmony_ci struct sysc_address *disabled_module; 31368c2ecf20Sopenharmony_ci struct list_head *pos; 31378c2ecf20Sopenharmony_ci int error = 0; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci mutex_lock(&sysc_soc->list_lock); 31408c2ecf20Sopenharmony_ci list_for_each(pos, &sysc_soc->disabled_modules) { 31418c2ecf20Sopenharmony_ci disabled_module = list_entry(pos, struct sysc_address, node); 31428c2ecf20Sopenharmony_ci if (ddata->module_pa == disabled_module->base) { 31438c2ecf20Sopenharmony_ci dev_dbg(ddata->dev, "module disabled for this SoC\n"); 31448c2ecf20Sopenharmony_ci error = -ENODEV; 31458c2ecf20Sopenharmony_ci break; 31468c2ecf20Sopenharmony_ci } 31478c2ecf20Sopenharmony_ci } 31488c2ecf20Sopenharmony_ci mutex_unlock(&sysc_soc->list_lock); 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci return error; 31518c2ecf20Sopenharmony_ci} 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci/* 31548c2ecf20Sopenharmony_ci * Ignore timers tagged with no-reset and no-idle. These are likely in use, 31558c2ecf20Sopenharmony_ci * for example by drivers/clocksource/timer-ti-dm-systimer.c. If more checks 31568c2ecf20Sopenharmony_ci * are needed, we could also look at the timer register configuration. 31578c2ecf20Sopenharmony_ci */ 31588c2ecf20Sopenharmony_cistatic int sysc_check_active_timer(struct sysc *ddata) 31598c2ecf20Sopenharmony_ci{ 31608c2ecf20Sopenharmony_ci int error; 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci if (ddata->cap->type != TI_SYSC_OMAP2_TIMER && 31638c2ecf20Sopenharmony_ci ddata->cap->type != TI_SYSC_OMAP4_TIMER) 31648c2ecf20Sopenharmony_ci return 0; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci /* 31678c2ecf20Sopenharmony_ci * Quirk for omap3 beagleboard revision A to B4 to use gpt12. 31688c2ecf20Sopenharmony_ci * Revision C and later are fixed with commit 23885389dbbb ("ARM: 31698c2ecf20Sopenharmony_ci * dts: Fix timer regression for beagleboard revision c"). This all 31708c2ecf20Sopenharmony_ci * can be dropped if we stop supporting old beagleboard revisions 31718c2ecf20Sopenharmony_ci * A to B4 at some point. 31728c2ecf20Sopenharmony_ci */ 31738c2ecf20Sopenharmony_ci if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) 31748c2ecf20Sopenharmony_ci error = -ENXIO; 31758c2ecf20Sopenharmony_ci else 31768c2ecf20Sopenharmony_ci error = -EBUSY; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci if ((ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) && 31798c2ecf20Sopenharmony_ci (ddata->cfg.quirks & SYSC_QUIRK_NO_IDLE)) 31808c2ecf20Sopenharmony_ci return error; 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci return 0; 31838c2ecf20Sopenharmony_ci} 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_cistatic const struct of_device_id sysc_match_table[] = { 31868c2ecf20Sopenharmony_ci { .compatible = "simple-bus", }, 31878c2ecf20Sopenharmony_ci { /* sentinel */ }, 31888c2ecf20Sopenharmony_ci}; 31898c2ecf20Sopenharmony_ci 31908c2ecf20Sopenharmony_cistatic int sysc_probe(struct platform_device *pdev) 31918c2ecf20Sopenharmony_ci{ 31928c2ecf20Sopenharmony_ci struct ti_sysc_platform_data *pdata = dev_get_platdata(&pdev->dev); 31938c2ecf20Sopenharmony_ci struct sysc *ddata; 31948c2ecf20Sopenharmony_ci int error; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); 31978c2ecf20Sopenharmony_ci if (!ddata) 31988c2ecf20Sopenharmony_ci return -ENOMEM; 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci ddata->dev = &pdev->dev; 32018c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, ddata); 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci error = sysc_init_static_data(ddata); 32048c2ecf20Sopenharmony_ci if (error) 32058c2ecf20Sopenharmony_ci return error; 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci error = sysc_init_match(ddata); 32088c2ecf20Sopenharmony_ci if (error) 32098c2ecf20Sopenharmony_ci return error; 32108c2ecf20Sopenharmony_ci 32118c2ecf20Sopenharmony_ci error = sysc_init_dts_quirks(ddata); 32128c2ecf20Sopenharmony_ci if (error) 32138c2ecf20Sopenharmony_ci return error; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci error = sysc_map_and_check_registers(ddata); 32168c2ecf20Sopenharmony_ci if (error) 32178c2ecf20Sopenharmony_ci return error; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci error = sysc_init_sysc_mask(ddata); 32208c2ecf20Sopenharmony_ci if (error) 32218c2ecf20Sopenharmony_ci return error; 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci error = sysc_init_idlemodes(ddata); 32248c2ecf20Sopenharmony_ci if (error) 32258c2ecf20Sopenharmony_ci return error; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci error = sysc_init_syss_mask(ddata); 32288c2ecf20Sopenharmony_ci if (error) 32298c2ecf20Sopenharmony_ci return error; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci error = sysc_init_pdata(ddata); 32328c2ecf20Sopenharmony_ci if (error) 32338c2ecf20Sopenharmony_ci return error; 32348c2ecf20Sopenharmony_ci 32358c2ecf20Sopenharmony_ci sysc_init_early_quirks(ddata); 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci error = sysc_check_disabled_devices(ddata); 32388c2ecf20Sopenharmony_ci if (error) 32398c2ecf20Sopenharmony_ci return error; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci error = sysc_check_active_timer(ddata); 32428c2ecf20Sopenharmony_ci if (error == -ENXIO) 32438c2ecf20Sopenharmony_ci ddata->reserved = true; 32448c2ecf20Sopenharmony_ci else if (error) 32458c2ecf20Sopenharmony_ci return error; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci error = sysc_get_clocks(ddata); 32488c2ecf20Sopenharmony_ci if (error) 32498c2ecf20Sopenharmony_ci return error; 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci error = sysc_init_resets(ddata); 32528c2ecf20Sopenharmony_ci if (error) 32538c2ecf20Sopenharmony_ci goto unprepare; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci error = sysc_init_module(ddata); 32568c2ecf20Sopenharmony_ci if (error) 32578c2ecf20Sopenharmony_ci goto unprepare; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci pm_runtime_enable(ddata->dev); 32608c2ecf20Sopenharmony_ci error = pm_runtime_get_sync(ddata->dev); 32618c2ecf20Sopenharmony_ci if (error < 0) { 32628c2ecf20Sopenharmony_ci pm_runtime_put_noidle(ddata->dev); 32638c2ecf20Sopenharmony_ci pm_runtime_disable(ddata->dev); 32648c2ecf20Sopenharmony_ci goto unprepare; 32658c2ecf20Sopenharmony_ci } 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci /* Balance use counts as PM runtime should have enabled these all */ 32688c2ecf20Sopenharmony_ci if (!(ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT)) 32698c2ecf20Sopenharmony_ci reset_control_assert(ddata->rsts); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci if (!(ddata->cfg.quirks & 32728c2ecf20Sopenharmony_ci (SYSC_QUIRK_NO_IDLE | SYSC_QUIRK_NO_IDLE_ON_INIT))) { 32738c2ecf20Sopenharmony_ci sysc_disable_main_clocks(ddata); 32748c2ecf20Sopenharmony_ci sysc_disable_opt_clocks(ddata); 32758c2ecf20Sopenharmony_ci sysc_clkdm_allow_idle(ddata); 32768c2ecf20Sopenharmony_ci } 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci sysc_show_registers(ddata); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci ddata->dev->type = &sysc_device_type; 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci if (!ddata->reserved) { 32838c2ecf20Sopenharmony_ci error = of_platform_populate(ddata->dev->of_node, 32848c2ecf20Sopenharmony_ci sysc_match_table, 32858c2ecf20Sopenharmony_ci pdata ? pdata->auxdata : NULL, 32868c2ecf20Sopenharmony_ci ddata->dev); 32878c2ecf20Sopenharmony_ci if (error) 32888c2ecf20Sopenharmony_ci goto err; 32898c2ecf20Sopenharmony_ci } 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&ddata->idle_work, ti_sysc_idle); 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci /* At least earlycon won't survive without deferred idle */ 32948c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & (SYSC_QUIRK_NO_IDLE | 32958c2ecf20Sopenharmony_ci SYSC_QUIRK_NO_IDLE_ON_INIT | 32968c2ecf20Sopenharmony_ci SYSC_QUIRK_NO_RESET_ON_INIT)) { 32978c2ecf20Sopenharmony_ci schedule_delayed_work(&ddata->idle_work, 3000); 32988c2ecf20Sopenharmony_ci } else { 32998c2ecf20Sopenharmony_ci pm_runtime_put(&pdev->dev); 33008c2ecf20Sopenharmony_ci } 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci if (ddata->cfg.quirks & SYSC_QUIRK_REINIT_ON_CTX_LOST) 33038c2ecf20Sopenharmony_ci sysc_add_restored(ddata); 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci return 0; 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_cierr: 33088c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 33098c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 33108c2ecf20Sopenharmony_ciunprepare: 33118c2ecf20Sopenharmony_ci sysc_unprepare(ddata); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci return error; 33148c2ecf20Sopenharmony_ci} 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_cistatic int sysc_remove(struct platform_device *pdev) 33178c2ecf20Sopenharmony_ci{ 33188c2ecf20Sopenharmony_ci struct sysc *ddata = platform_get_drvdata(pdev); 33198c2ecf20Sopenharmony_ci int error; 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci /* Device can still be enabled, see deferred idle quirk in probe */ 33228c2ecf20Sopenharmony_ci if (cancel_delayed_work_sync(&ddata->idle_work)) 33238c2ecf20Sopenharmony_ci ti_sysc_idle(&ddata->idle_work.work); 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci error = pm_runtime_get_sync(ddata->dev); 33268c2ecf20Sopenharmony_ci if (error < 0) { 33278c2ecf20Sopenharmony_ci pm_runtime_put_noidle(ddata->dev); 33288c2ecf20Sopenharmony_ci pm_runtime_disable(ddata->dev); 33298c2ecf20Sopenharmony_ci goto unprepare; 33308c2ecf20Sopenharmony_ci } 33318c2ecf20Sopenharmony_ci 33328c2ecf20Sopenharmony_ci of_platform_depopulate(&pdev->dev); 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 33358c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci if (!reset_control_status(ddata->rsts)) 33388c2ecf20Sopenharmony_ci reset_control_assert(ddata->rsts); 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ciunprepare: 33418c2ecf20Sopenharmony_ci sysc_unprepare(ddata); 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci return 0; 33448c2ecf20Sopenharmony_ci} 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_cistatic const struct of_device_id sysc_match[] = { 33478c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap2", .data = &sysc_omap2, }, 33488c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap2-timer", .data = &sysc_omap2_timer, }, 33498c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap4", .data = &sysc_omap4, }, 33508c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap4-timer", .data = &sysc_omap4_timer, }, 33518c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap4-simple", .data = &sysc_omap4_simple, }, 33528c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap3430-sr", .data = &sysc_34xx_sr, }, 33538c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap3630-sr", .data = &sysc_36xx_sr, }, 33548c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap4-sr", .data = &sysc_omap4_sr, }, 33558c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, 33568c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, 33578c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, 33588c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, }, 33598c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-usb-host-fs", 33608c2ecf20Sopenharmony_ci .data = &sysc_omap4_usb_host_fs, }, 33618c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, 33628c2ecf20Sopenharmony_ci { .compatible = "ti,sysc-pruss", .data = &sysc_pruss, }, 33638c2ecf20Sopenharmony_ci { }, 33648c2ecf20Sopenharmony_ci}; 33658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sysc_match); 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_cistatic struct platform_driver sysc_driver = { 33688c2ecf20Sopenharmony_ci .probe = sysc_probe, 33698c2ecf20Sopenharmony_ci .remove = sysc_remove, 33708c2ecf20Sopenharmony_ci .driver = { 33718c2ecf20Sopenharmony_ci .name = "ti-sysc", 33728c2ecf20Sopenharmony_ci .of_match_table = sysc_match, 33738c2ecf20Sopenharmony_ci .pm = &sysc_pm_ops, 33748c2ecf20Sopenharmony_ci }, 33758c2ecf20Sopenharmony_ci}; 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_cistatic int __init sysc_init(void) 33788c2ecf20Sopenharmony_ci{ 33798c2ecf20Sopenharmony_ci bus_register_notifier(&platform_bus_type, &sysc_nb); 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci return platform_driver_register(&sysc_driver); 33828c2ecf20Sopenharmony_ci} 33838c2ecf20Sopenharmony_cimodule_init(sysc_init); 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_cistatic void __exit sysc_exit(void) 33868c2ecf20Sopenharmony_ci{ 33878c2ecf20Sopenharmony_ci bus_unregister_notifier(&platform_bus_type, &sysc_nb); 33888c2ecf20Sopenharmony_ci platform_driver_unregister(&sysc_driver); 33898c2ecf20Sopenharmony_ci sysc_cleanup_static_data(); 33908c2ecf20Sopenharmony_ci} 33918c2ecf20Sopenharmony_cimodule_exit(sysc_exit); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI sysc interconnect target driver"); 33948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3395