18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * OMAP2+ PRM driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 68c2ecf20Sopenharmony_ci * Tero Kristo <t-kristo@ti.com> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/pm_domain.h> 188c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/platform_data/ti-prm.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cienum omap_prm_domain_mode { 248c2ecf20Sopenharmony_ci OMAP_PRMD_OFF, 258c2ecf20Sopenharmony_ci OMAP_PRMD_RETENTION, 268c2ecf20Sopenharmony_ci OMAP_PRMD_ON_INACTIVE, 278c2ecf20Sopenharmony_ci OMAP_PRMD_ON_ACTIVE, 288c2ecf20Sopenharmony_ci}; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistruct omap_prm_domain_map { 318c2ecf20Sopenharmony_ci unsigned int usable_modes; /* Mask of hardware supported modes */ 328c2ecf20Sopenharmony_ci unsigned long statechange:1; /* Optional low-power state change */ 338c2ecf20Sopenharmony_ci unsigned long logicretstate:1; /* Optional logic off mode */ 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct omap_prm_domain { 378c2ecf20Sopenharmony_ci struct device *dev; 388c2ecf20Sopenharmony_ci struct omap_prm *prm; 398c2ecf20Sopenharmony_ci struct generic_pm_domain pd; 408c2ecf20Sopenharmony_ci u16 pwrstctrl; 418c2ecf20Sopenharmony_ci u16 pwrstst; 428c2ecf20Sopenharmony_ci const struct omap_prm_domain_map *cap; 438c2ecf20Sopenharmony_ci u32 pwrstctrl_saved; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct omap_rst_map { 478c2ecf20Sopenharmony_ci s8 rst; 488c2ecf20Sopenharmony_ci s8 st; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct omap_prm_data { 528c2ecf20Sopenharmony_ci u32 base; 538c2ecf20Sopenharmony_ci const char *name; 548c2ecf20Sopenharmony_ci const char *clkdm_name; 558c2ecf20Sopenharmony_ci u16 pwrstctrl; 568c2ecf20Sopenharmony_ci u16 pwrstst; 578c2ecf20Sopenharmony_ci const struct omap_prm_domain_map *dmap; 588c2ecf20Sopenharmony_ci u16 rstctrl; 598c2ecf20Sopenharmony_ci u16 rstst; 608c2ecf20Sopenharmony_ci const struct omap_rst_map *rstmap; 618c2ecf20Sopenharmony_ci u8 flags; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistruct omap_prm { 658c2ecf20Sopenharmony_ci const struct omap_prm_data *data; 668c2ecf20Sopenharmony_ci void __iomem *base; 678c2ecf20Sopenharmony_ci struct omap_prm_domain *prmd; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct omap_reset_data { 718c2ecf20Sopenharmony_ci struct reset_controller_dev rcdev; 728c2ecf20Sopenharmony_ci struct omap_prm *prm; 738c2ecf20Sopenharmony_ci u32 mask; 748c2ecf20Sopenharmony_ci spinlock_t lock; 758c2ecf20Sopenharmony_ci struct clockdomain *clkdm; 768c2ecf20Sopenharmony_ci struct device *dev; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd) 808c2ecf20Sopenharmony_ci#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define OMAP_MAX_RESETS 8 838c2ecf20Sopenharmony_ci#define OMAP_RESET_MAX_WAIT 10000 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define OMAP_PRM_HAS_RSTCTRL BIT(0) 868c2ecf20Sopenharmony_ci#define OMAP_PRM_HAS_RSTST BIT(1) 878c2ecf20Sopenharmony_ci#define OMAP_PRM_HAS_NO_CLKDM BIT(2) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST) 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define PRM_STATE_MAX_WAIT 10000 928c2ecf20Sopenharmony_ci#define PRM_LOGICRETSTATE BIT(2) 938c2ecf20Sopenharmony_ci#define PRM_LOWPOWERSTATECHANGE BIT(4) 948c2ecf20Sopenharmony_ci#define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#define PRM_ST_INTRANSITION BIT(20) 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_all = { 998c2ecf20Sopenharmony_ci .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | 1008c2ecf20Sopenharmony_ci BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF), 1018c2ecf20Sopenharmony_ci .statechange = 1, 1028c2ecf20Sopenharmony_ci .logicretstate = 1, 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_noinact = { 1068c2ecf20Sopenharmony_ci .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) | 1078c2ecf20Sopenharmony_ci BIT(OMAP_PRMD_OFF), 1088c2ecf20Sopenharmony_ci .statechange = 1, 1098c2ecf20Sopenharmony_ci .logicretstate = 1, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_nooff = { 1138c2ecf20Sopenharmony_ci .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | 1148c2ecf20Sopenharmony_ci BIT(OMAP_PRMD_RETENTION), 1158c2ecf20Sopenharmony_ci .statechange = 1, 1168c2ecf20Sopenharmony_ci .logicretstate = 1, 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct omap_prm_domain_map omap_prm_onoff_noauto = { 1208c2ecf20Sopenharmony_ci .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF), 1218c2ecf20Sopenharmony_ci .statechange = 1, 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic const struct omap_rst_map rst_map_0[] = { 1258c2ecf20Sopenharmony_ci { .rst = 0, .st = 0 }, 1268c2ecf20Sopenharmony_ci { .rst = -1 }, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const struct omap_rst_map rst_map_01[] = { 1308c2ecf20Sopenharmony_ci { .rst = 0, .st = 0 }, 1318c2ecf20Sopenharmony_ci { .rst = 1, .st = 1 }, 1328c2ecf20Sopenharmony_ci { .rst = -1 }, 1338c2ecf20Sopenharmony_ci}; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic const struct omap_rst_map rst_map_012[] = { 1368c2ecf20Sopenharmony_ci { .rst = 0, .st = 0 }, 1378c2ecf20Sopenharmony_ci { .rst = 1, .st = 1 }, 1388c2ecf20Sopenharmony_ci { .rst = 2, .st = 2 }, 1398c2ecf20Sopenharmony_ci { .rst = -1 }, 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic const struct omap_prm_data omap4_prm_data[] = { 1438c2ecf20Sopenharmony_ci { .name = "tesla", .base = 0x4a306400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1448c2ecf20Sopenharmony_ci { 1458c2ecf20Sopenharmony_ci .name = "abe", .base = 0x4a306500, 1468c2ecf20Sopenharmony_ci .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all, 1478c2ecf20Sopenharmony_ci }, 1488c2ecf20Sopenharmony_ci { .name = "core", .base = 0x4a306700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", .rstmap = rst_map_012 }, 1498c2ecf20Sopenharmony_ci { .name = "ivahd", .base = 0x4a306f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 1508c2ecf20Sopenharmony_ci { .name = "device", .base = 0x4a307b00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 1518c2ecf20Sopenharmony_ci { }, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const struct omap_prm_data omap5_prm_data[] = { 1558c2ecf20Sopenharmony_ci { .name = "dsp", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1568c2ecf20Sopenharmony_ci { 1578c2ecf20Sopenharmony_ci .name = "abe", .base = 0x4ae06500, 1588c2ecf20Sopenharmony_ci .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff, 1598c2ecf20Sopenharmony_ci }, 1608c2ecf20Sopenharmony_ci { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", .rstmap = rst_map_012 }, 1618c2ecf20Sopenharmony_ci { .name = "iva", .base = 0x4ae07200, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 1628c2ecf20Sopenharmony_ci { .name = "device", .base = 0x4ae07c00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 1638c2ecf20Sopenharmony_ci { }, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic const struct omap_prm_data dra7_prm_data[] = { 1678c2ecf20Sopenharmony_ci { .name = "dsp1", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1688c2ecf20Sopenharmony_ci { .name = "ipu", .base = 0x4ae06500, .rstctrl = 0x10, .rstst = 0x14, .clkdm_name = "ipu1", .rstmap = rst_map_012 }, 1698c2ecf20Sopenharmony_ci { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu2", .rstmap = rst_map_012 }, 1708c2ecf20Sopenharmony_ci { .name = "iva", .base = 0x4ae06f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 1718c2ecf20Sopenharmony_ci { .name = "dsp2", .base = 0x4ae07b00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1728c2ecf20Sopenharmony_ci { .name = "eve1", .base = 0x4ae07b40, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1738c2ecf20Sopenharmony_ci { .name = "eve2", .base = 0x4ae07b80, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1748c2ecf20Sopenharmony_ci { .name = "eve3", .base = 0x4ae07bc0, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1758c2ecf20Sopenharmony_ci { .name = "eve4", .base = 0x4ae07c00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 1768c2ecf20Sopenharmony_ci { }, 1778c2ecf20Sopenharmony_ci}; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const struct omap_rst_map am3_per_rst_map[] = { 1808c2ecf20Sopenharmony_ci { .rst = 1 }, 1818c2ecf20Sopenharmony_ci { .rst = -1 }, 1828c2ecf20Sopenharmony_ci}; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic const struct omap_rst_map am3_wkup_rst_map[] = { 1858c2ecf20Sopenharmony_ci { .rst = 3, .st = 5 }, 1868c2ecf20Sopenharmony_ci { .rst = -1 }, 1878c2ecf20Sopenharmony_ci}; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic const struct omap_prm_data am3_prm_data[] = { 1908c2ecf20Sopenharmony_ci { .name = "per", .base = 0x44e00c00, .rstctrl = 0x0, .rstmap = am3_per_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" }, 1918c2ecf20Sopenharmony_ci { .name = "wkup", .base = 0x44e00d00, .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 1928c2ecf20Sopenharmony_ci { .name = "device", .base = 0x44e00f00, .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 1938c2ecf20Sopenharmony_ci { 1948c2ecf20Sopenharmony_ci .name = "gfx", .base = 0x44e01100, 1958c2ecf20Sopenharmony_ci .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact, 1968c2ecf20Sopenharmony_ci .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci { }, 1998c2ecf20Sopenharmony_ci}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic const struct omap_rst_map am4_per_rst_map[] = { 2028c2ecf20Sopenharmony_ci { .rst = 1, .st = 0 }, 2038c2ecf20Sopenharmony_ci { .rst = -1 }, 2048c2ecf20Sopenharmony_ci}; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic const struct omap_rst_map am4_device_rst_map[] = { 2078c2ecf20Sopenharmony_ci { .rst = 0, .st = 1 }, 2088c2ecf20Sopenharmony_ci { .rst = 1, .st = 0 }, 2098c2ecf20Sopenharmony_ci { .rst = -1 }, 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic const struct omap_prm_data am4_prm_data[] = { 2138c2ecf20Sopenharmony_ci { 2148c2ecf20Sopenharmony_ci .name = "gfx", .base = 0x44df0400, 2158c2ecf20Sopenharmony_ci .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, 2168c2ecf20Sopenharmony_ci .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", 2178c2ecf20Sopenharmony_ci }, 2188c2ecf20Sopenharmony_ci { .name = "per", .base = 0x44df0800, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, .clkdm_name = "pruss_ocp" }, 2198c2ecf20Sopenharmony_ci { .name = "wkup", .base = 0x44df2000, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_NO_CLKDM }, 2208c2ecf20Sopenharmony_ci { .name = "device", .base = 0x44df4000, .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 2218c2ecf20Sopenharmony_ci { }, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic const struct of_device_id omap_prm_id_table[] = { 2258c2ecf20Sopenharmony_ci { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data }, 2268c2ecf20Sopenharmony_ci { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data }, 2278c2ecf20Sopenharmony_ci { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data }, 2288c2ecf20Sopenharmony_ci { .compatible = "ti,am3-prm-inst", .data = am3_prm_data }, 2298c2ecf20Sopenharmony_ci { .compatible = "ti,am4-prm-inst", .data = am4_prm_data }, 2308c2ecf20Sopenharmony_ci { }, 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#ifdef DEBUG 2348c2ecf20Sopenharmony_cistatic void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 2358c2ecf20Sopenharmony_ci const char *desc) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci dev_dbg(prmd->dev, "%s %s: %08x/%08x\n", 2388c2ecf20Sopenharmony_ci prmd->pd.name, desc, 2398c2ecf20Sopenharmony_ci readl_relaxed(prmd->prm->base + prmd->pwrstctrl), 2408c2ecf20Sopenharmony_ci readl_relaxed(prmd->prm->base + prmd->pwrstst)); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci#else 2438c2ecf20Sopenharmony_cistatic inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd, 2448c2ecf20Sopenharmony_ci const char *desc) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci#endif 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int omap_prm_domain_power_on(struct generic_pm_domain *domain) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct omap_prm_domain *prmd; 2528c2ecf20Sopenharmony_ci int ret; 2538c2ecf20Sopenharmony_ci u32 v; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci prmd = genpd_to_prm_domain(domain); 2568c2ecf20Sopenharmony_ci if (!prmd->cap) 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci omap_prm_domain_show_state(prmd, "on: previous state"); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (prmd->pwrstctrl_saved) 2628c2ecf20Sopenharmony_ci v = prmd->pwrstctrl_saved; 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci writel_relaxed(v | OMAP_PRMD_ON_ACTIVE, 2678c2ecf20Sopenharmony_ci prmd->prm->base + prmd->pwrstctrl); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* wait for the transition bit to get cleared */ 2708c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, 2718c2ecf20Sopenharmony_ci v, !(v & PRM_ST_INTRANSITION), 1, 2728c2ecf20Sopenharmony_ci PRM_STATE_MAX_WAIT); 2738c2ecf20Sopenharmony_ci if (ret) 2748c2ecf20Sopenharmony_ci dev_err(prmd->dev, "%s: %s timed out\n", 2758c2ecf20Sopenharmony_ci prmd->pd.name, __func__); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci omap_prm_domain_show_state(prmd, "on: new state"); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci/* No need to check for holes in the mask for the lowest mode */ 2838c2ecf20Sopenharmony_cistatic int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci return __ffs(prmd->cap->usable_modes); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int omap_prm_domain_power_off(struct generic_pm_domain *domain) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct omap_prm_domain *prmd; 2918c2ecf20Sopenharmony_ci int ret; 2928c2ecf20Sopenharmony_ci u32 v; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci prmd = genpd_to_prm_domain(domain); 2958c2ecf20Sopenharmony_ci if (!prmd->cap) 2968c2ecf20Sopenharmony_ci return 0; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci omap_prm_domain_show_state(prmd, "off: previous state"); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); 3018c2ecf20Sopenharmony_ci prmd->pwrstctrl_saved = v; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci v &= ~PRM_POWERSTATE_MASK; 3048c2ecf20Sopenharmony_ci v |= omap_prm_domain_find_lowest(prmd); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (prmd->cap->statechange) 3078c2ecf20Sopenharmony_ci v |= PRM_LOWPOWERSTATECHANGE; 3088c2ecf20Sopenharmony_ci if (prmd->cap->logicretstate) 3098c2ecf20Sopenharmony_ci v &= ~PRM_LOGICRETSTATE; 3108c2ecf20Sopenharmony_ci else 3118c2ecf20Sopenharmony_ci v |= PRM_LOGICRETSTATE; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* wait for the transition bit to get cleared */ 3168c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, 3178c2ecf20Sopenharmony_ci v, !(v & PRM_ST_INTRANSITION), 1, 3188c2ecf20Sopenharmony_ci PRM_STATE_MAX_WAIT); 3198c2ecf20Sopenharmony_ci if (ret) 3208c2ecf20Sopenharmony_ci dev_warn(prmd->dev, "%s: %s timed out\n", 3218c2ecf20Sopenharmony_ci __func__, prmd->pd.name); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci omap_prm_domain_show_state(prmd, "off: new state"); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci return 0; 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, 3298c2ecf20Sopenharmony_ci struct device *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct generic_pm_domain_data *genpd_data; 3328c2ecf20Sopenharmony_ci struct of_phandle_args pd_args; 3338c2ecf20Sopenharmony_ci struct omap_prm_domain *prmd; 3348c2ecf20Sopenharmony_ci struct device_node *np; 3358c2ecf20Sopenharmony_ci int ret; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci prmd = genpd_to_prm_domain(domain); 3388c2ecf20Sopenharmony_ci np = dev->of_node; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ret = of_parse_phandle_with_args(np, "power-domains", 3418c2ecf20Sopenharmony_ci "#power-domain-cells", 0, &pd_args); 3428c2ecf20Sopenharmony_ci if (ret < 0) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (pd_args.args_count != 0) 3468c2ecf20Sopenharmony_ci dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", 3478c2ecf20Sopenharmony_ci prmd->pd.name, pd_args.args_count); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci genpd_data = dev_gpd_data(dev); 3508c2ecf20Sopenharmony_ci genpd_data->data = NULL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return 0; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic void omap_prm_domain_detach_dev(struct generic_pm_domain *domain, 3568c2ecf20Sopenharmony_ci struct device *dev) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct generic_pm_domain_data *genpd_data; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci genpd_data = dev_gpd_data(dev); 3618c2ecf20Sopenharmony_ci genpd_data->data = NULL; 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct omap_prm_domain *prmd; 3678c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 3688c2ecf20Sopenharmony_ci const struct omap_prm_data *data; 3698c2ecf20Sopenharmony_ci const char *name; 3708c2ecf20Sopenharmony_ci int error; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (!of_find_property(dev->of_node, "#power-domain-cells", NULL)) 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci of_node_put(dev->of_node); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL); 3788c2ecf20Sopenharmony_ci if (!prmd) 3798c2ecf20Sopenharmony_ci return -ENOMEM; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci data = prm->data; 3828c2ecf20Sopenharmony_ci name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", 3838c2ecf20Sopenharmony_ci data->name); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci prmd->dev = dev; 3868c2ecf20Sopenharmony_ci prmd->prm = prm; 3878c2ecf20Sopenharmony_ci prmd->cap = prmd->prm->data->dmap; 3888c2ecf20Sopenharmony_ci prmd->pwrstctrl = prmd->prm->data->pwrstctrl; 3898c2ecf20Sopenharmony_ci prmd->pwrstst = prmd->prm->data->pwrstst; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci prmd->pd.name = name; 3928c2ecf20Sopenharmony_ci prmd->pd.power_on = omap_prm_domain_power_on; 3938c2ecf20Sopenharmony_ci prmd->pd.power_off = omap_prm_domain_power_off; 3948c2ecf20Sopenharmony_ci prmd->pd.attach_dev = omap_prm_domain_attach_dev; 3958c2ecf20Sopenharmony_ci prmd->pd.detach_dev = omap_prm_domain_detach_dev; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci pm_genpd_init(&prmd->pd, NULL, true); 3988c2ecf20Sopenharmony_ci error = of_genpd_add_provider_simple(np, &prmd->pd); 3998c2ecf20Sopenharmony_ci if (error) 4008c2ecf20Sopenharmony_ci pm_genpd_remove(&prmd->pd); 4018c2ecf20Sopenharmony_ci else 4028c2ecf20Sopenharmony_ci prm->prmd = prmd; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci return error; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci if (reset->mask & BIT(id)) 4108c2ecf20Sopenharmony_ci return true; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return false; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int omap_reset_get_st_bit(struct omap_reset_data *reset, 4168c2ecf20Sopenharmony_ci unsigned long id) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci const struct omap_rst_map *map = reset->prm->data->rstmap; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci while (map->rst >= 0) { 4218c2ecf20Sopenharmony_ci if (map->rst == id) 4228c2ecf20Sopenharmony_ci return map->st; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci map++; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return id; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int omap_reset_status(struct reset_controller_dev *rcdev, 4318c2ecf20Sopenharmony_ci unsigned long id) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct omap_reset_data *reset = to_omap_reset_data(rcdev); 4348c2ecf20Sopenharmony_ci u32 v; 4358c2ecf20Sopenharmony_ci int st_bit = omap_reset_get_st_bit(reset, id); 4368c2ecf20Sopenharmony_ci bool has_rstst = reset->prm->data->rstst || 4378c2ecf20Sopenharmony_ci (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* Check if we have rstst */ 4408c2ecf20Sopenharmony_ci if (!has_rstst) 4418c2ecf20Sopenharmony_ci return -ENOTSUPP; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Check if hw reset line is asserted */ 4448c2ecf20Sopenharmony_ci v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 4458c2ecf20Sopenharmony_ci if (v & BIT(id)) 4468c2ecf20Sopenharmony_ci return 1; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* 4498c2ecf20Sopenharmony_ci * Check reset status, high value means reset sequence has been 4508c2ecf20Sopenharmony_ci * completed successfully so we can return 0 here (reset deasserted) 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci v = readl_relaxed(reset->prm->base + reset->prm->data->rstst); 4538c2ecf20Sopenharmony_ci v >>= st_bit; 4548c2ecf20Sopenharmony_ci v &= 1; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return !v; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic int omap_reset_assert(struct reset_controller_dev *rcdev, 4608c2ecf20Sopenharmony_ci unsigned long id) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci struct omap_reset_data *reset = to_omap_reset_data(rcdev); 4638c2ecf20Sopenharmony_ci u32 v; 4648c2ecf20Sopenharmony_ci unsigned long flags; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci /* assert the reset control line */ 4678c2ecf20Sopenharmony_ci spin_lock_irqsave(&reset->lock, flags); 4688c2ecf20Sopenharmony_ci v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 4698c2ecf20Sopenharmony_ci v |= 1 << id; 4708c2ecf20Sopenharmony_ci writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 4718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&reset->lock, flags); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return 0; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic int omap_reset_deassert(struct reset_controller_dev *rcdev, 4778c2ecf20Sopenharmony_ci unsigned long id) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct omap_reset_data *reset = to_omap_reset_data(rcdev); 4808c2ecf20Sopenharmony_ci u32 v; 4818c2ecf20Sopenharmony_ci int st_bit; 4828c2ecf20Sopenharmony_ci bool has_rstst; 4838c2ecf20Sopenharmony_ci unsigned long flags; 4848c2ecf20Sopenharmony_ci struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev); 4858c2ecf20Sopenharmony_ci int ret = 0; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Nothing to do if the reset is already deasserted */ 4888c2ecf20Sopenharmony_ci if (!omap_reset_status(rcdev, id)) 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci has_rstst = reset->prm->data->rstst || 4928c2ecf20Sopenharmony_ci (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (has_rstst) { 4958c2ecf20Sopenharmony_ci st_bit = omap_reset_get_st_bit(reset, id); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci /* Clear the reset status by writing 1 to the status bit */ 4988c2ecf20Sopenharmony_ci v = 1 << st_bit; 4998c2ecf20Sopenharmony_ci writel_relaxed(v, reset->prm->base + reset->prm->data->rstst); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (reset->clkdm) 5038c2ecf20Sopenharmony_ci pdata->clkdm_deny_idle(reset->clkdm); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci /* de-assert the reset control line */ 5068c2ecf20Sopenharmony_ci spin_lock_irqsave(&reset->lock, flags); 5078c2ecf20Sopenharmony_ci v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 5088c2ecf20Sopenharmony_ci v &= ~(1 << id); 5098c2ecf20Sopenharmony_ci writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 5108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&reset->lock, flags); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* wait for the reset bit to clear */ 5138c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(reset->prm->base + 5148c2ecf20Sopenharmony_ci reset->prm->data->rstctrl, 5158c2ecf20Sopenharmony_ci v, !(v & BIT(id)), 1, 5168c2ecf20Sopenharmony_ci OMAP_RESET_MAX_WAIT); 5178c2ecf20Sopenharmony_ci if (ret) 5188c2ecf20Sopenharmony_ci pr_err("%s: timedout waiting for %s:%lu\n", __func__, 5198c2ecf20Sopenharmony_ci reset->prm->data->name, id); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* wait for the status to be set */ 5228c2ecf20Sopenharmony_ci if (has_rstst) { 5238c2ecf20Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(reset->prm->base + 5248c2ecf20Sopenharmony_ci reset->prm->data->rstst, 5258c2ecf20Sopenharmony_ci v, v & BIT(st_bit), 1, 5268c2ecf20Sopenharmony_ci OMAP_RESET_MAX_WAIT); 5278c2ecf20Sopenharmony_ci if (ret) 5288c2ecf20Sopenharmony_ci pr_err("%s: timedout waiting for %s:%lu\n", __func__, 5298c2ecf20Sopenharmony_ci reset->prm->data->name, id); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (reset->clkdm) 5338c2ecf20Sopenharmony_ci pdata->clkdm_allow_idle(reset->clkdm); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return ret; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct reset_control_ops omap_reset_ops = { 5398c2ecf20Sopenharmony_ci .assert = omap_reset_assert, 5408c2ecf20Sopenharmony_ci .deassert = omap_reset_deassert, 5418c2ecf20Sopenharmony_ci .status = omap_reset_status, 5428c2ecf20Sopenharmony_ci}; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int omap_prm_reset_xlate(struct reset_controller_dev *rcdev, 5458c2ecf20Sopenharmony_ci const struct of_phandle_args *reset_spec) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci struct omap_reset_data *reset = to_omap_reset_data(rcdev); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (!_is_valid_reset(reset, reset_spec->args[0])) 5508c2ecf20Sopenharmony_ci return -EINVAL; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return reset_spec->args[0]; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic int omap_prm_reset_init(struct platform_device *pdev, 5568c2ecf20Sopenharmony_ci struct omap_prm *prm) 5578c2ecf20Sopenharmony_ci{ 5588c2ecf20Sopenharmony_ci struct omap_reset_data *reset; 5598c2ecf20Sopenharmony_ci const struct omap_rst_map *map; 5608c2ecf20Sopenharmony_ci struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev); 5618c2ecf20Sopenharmony_ci char buf[32]; 5628c2ecf20Sopenharmony_ci u32 v; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* 5658c2ecf20Sopenharmony_ci * Check if we have controllable resets. If either rstctrl is non-zero 5668c2ecf20Sopenharmony_ci * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register 5678c2ecf20Sopenharmony_ci * for the domain. 5688c2ecf20Sopenharmony_ci */ 5698c2ecf20Sopenharmony_ci if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL)) 5708c2ecf20Sopenharmony_ci return 0; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* Check if we have the pdata callbacks in place */ 5738c2ecf20Sopenharmony_ci if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle || 5748c2ecf20Sopenharmony_ci !pdata->clkdm_allow_idle) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci map = prm->data->rstmap; 5788c2ecf20Sopenharmony_ci if (!map) 5798c2ecf20Sopenharmony_ci return -EINVAL; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); 5828c2ecf20Sopenharmony_ci if (!reset) 5838c2ecf20Sopenharmony_ci return -ENOMEM; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci reset->rcdev.owner = THIS_MODULE; 5868c2ecf20Sopenharmony_ci reset->rcdev.ops = &omap_reset_ops; 5878c2ecf20Sopenharmony_ci reset->rcdev.of_node = pdev->dev.of_node; 5888c2ecf20Sopenharmony_ci reset->rcdev.nr_resets = OMAP_MAX_RESETS; 5898c2ecf20Sopenharmony_ci reset->rcdev.of_xlate = omap_prm_reset_xlate; 5908c2ecf20Sopenharmony_ci reset->rcdev.of_reset_n_cells = 1; 5918c2ecf20Sopenharmony_ci reset->dev = &pdev->dev; 5928c2ecf20Sopenharmony_ci spin_lock_init(&reset->lock); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci reset->prm = prm; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name : 5978c2ecf20Sopenharmony_ci prm->data->name); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) { 6008c2ecf20Sopenharmony_ci reset->clkdm = pdata->clkdm_lookup(buf); 6018c2ecf20Sopenharmony_ci if (!reset->clkdm) 6028c2ecf20Sopenharmony_ci return -EINVAL; 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci while (map->rst >= 0) { 6068c2ecf20Sopenharmony_ci reset->mask |= BIT(map->rst); 6078c2ecf20Sopenharmony_ci map++; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */ 6118c2ecf20Sopenharmony_ci if (prm->data->rstmap == rst_map_012) { 6128c2ecf20Sopenharmony_ci v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 6138c2ecf20Sopenharmony_ci if ((v & reset->mask) != reset->mask) { 6148c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v); 6158c2ecf20Sopenharmony_ci writel_relaxed(reset->mask, reset->prm->base + 6168c2ecf20Sopenharmony_ci reset->prm->data->rstctrl); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return devm_reset_controller_register(&pdev->dev, &reset->rcdev); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic int omap_prm_probe(struct platform_device *pdev) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct resource *res; 6268c2ecf20Sopenharmony_ci const struct omap_prm_data *data; 6278c2ecf20Sopenharmony_ci struct omap_prm *prm; 6288c2ecf20Sopenharmony_ci const struct of_device_id *match; 6298c2ecf20Sopenharmony_ci int ret; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6328c2ecf20Sopenharmony_ci if (!res) 6338c2ecf20Sopenharmony_ci return -ENODEV; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci match = of_match_device(omap_prm_id_table, &pdev->dev); 6368c2ecf20Sopenharmony_ci if (!match) 6378c2ecf20Sopenharmony_ci return -ENOTSUPP; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL); 6408c2ecf20Sopenharmony_ci if (!prm) 6418c2ecf20Sopenharmony_ci return -ENOMEM; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci data = match->data; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci while (data->base != res->start) { 6468c2ecf20Sopenharmony_ci if (!data->base) 6478c2ecf20Sopenharmony_ci return -EINVAL; 6488c2ecf20Sopenharmony_ci data++; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci prm->data = data; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci prm->base = devm_ioremap_resource(&pdev->dev, res); 6548c2ecf20Sopenharmony_ci if (IS_ERR(prm->base)) 6558c2ecf20Sopenharmony_ci return PTR_ERR(prm->base); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci ret = omap_prm_domain_init(&pdev->dev, prm); 6588c2ecf20Sopenharmony_ci if (ret) 6598c2ecf20Sopenharmony_ci return ret; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci ret = omap_prm_reset_init(pdev, prm); 6628c2ecf20Sopenharmony_ci if (ret) 6638c2ecf20Sopenharmony_ci goto err_domain; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return 0; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cierr_domain: 6688c2ecf20Sopenharmony_ci of_genpd_del_provider(pdev->dev.of_node); 6698c2ecf20Sopenharmony_ci pm_genpd_remove(&prm->prmd->pd); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci return ret; 6728c2ecf20Sopenharmony_ci} 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic struct platform_driver omap_prm_driver = { 6758c2ecf20Sopenharmony_ci .probe = omap_prm_probe, 6768c2ecf20Sopenharmony_ci .driver = { 6778c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 6788c2ecf20Sopenharmony_ci .of_match_table = omap_prm_id_table, 6798c2ecf20Sopenharmony_ci }, 6808c2ecf20Sopenharmony_ci}; 6818c2ecf20Sopenharmony_cibuiltin_platform_driver(omap_prm_driver); 682