Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * OMAP2+ PRM driver
0004  *
0005  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
0006  *  Tero Kristo <t-kristo@ti.com>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/clk.h>
0011 #include <linux/device.h>
0012 #include <linux/io.h>
0013 #include <linux/iopoll.h>
0014 #include <linux/module.h>
0015 #include <linux/of.h>
0016 #include <linux/of_device.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/pm_clock.h>
0019 #include <linux/pm_domain.h>
0020 #include <linux/reset-controller.h>
0021 #include <linux/delay.h>
0022 
0023 #include <linux/platform_data/ti-prm.h>
0024 
0025 enum omap_prm_domain_mode {
0026     OMAP_PRMD_OFF,
0027     OMAP_PRMD_RETENTION,
0028     OMAP_PRMD_ON_INACTIVE,
0029     OMAP_PRMD_ON_ACTIVE,
0030 };
0031 
0032 struct omap_prm_domain_map {
0033     unsigned int usable_modes;  /* Mask of hardware supported modes */
0034     unsigned long statechange:1;    /* Optional low-power state change */
0035     unsigned long logicretstate:1;  /* Optional logic off mode */
0036 };
0037 
0038 struct omap_prm_domain {
0039     struct device *dev;
0040     struct omap_prm *prm;
0041     struct generic_pm_domain pd;
0042     u16 pwrstctrl;
0043     u16 pwrstst;
0044     const struct omap_prm_domain_map *cap;
0045     u32 pwrstctrl_saved;
0046     unsigned int uses_pm_clk:1;
0047 };
0048 
0049 struct omap_rst_map {
0050     s8 rst;
0051     s8 st;
0052 };
0053 
0054 struct omap_prm_data {
0055     u32 base;
0056     const char *name;
0057     const char *clkdm_name;
0058     u16 pwrstctrl;
0059     u16 pwrstst;
0060     const struct omap_prm_domain_map *dmap;
0061     u16 rstctrl;
0062     u16 rstst;
0063     const struct omap_rst_map *rstmap;
0064     u8 flags;
0065 };
0066 
0067 struct omap_prm {
0068     const struct omap_prm_data *data;
0069     void __iomem *base;
0070     struct omap_prm_domain *prmd;
0071 };
0072 
0073 struct omap_reset_data {
0074     struct reset_controller_dev rcdev;
0075     struct omap_prm *prm;
0076     u32 mask;
0077     spinlock_t lock;
0078     struct clockdomain *clkdm;
0079     struct device *dev;
0080 };
0081 
0082 #define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
0083 #define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
0084 
0085 #define OMAP_MAX_RESETS     8
0086 #define OMAP_RESET_MAX_WAIT 10000
0087 
0088 #define OMAP_PRM_HAS_RSTCTRL    BIT(0)
0089 #define OMAP_PRM_HAS_RSTST  BIT(1)
0090 #define OMAP_PRM_HAS_NO_CLKDM   BIT(2)
0091 #define OMAP_PRM_RET_WHEN_IDLE  BIT(3)
0092 
0093 #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
0094 
0095 #define PRM_STATE_MAX_WAIT  10000
0096 #define PRM_LOGICRETSTATE   BIT(2)
0097 #define PRM_LOWPOWERSTATECHANGE BIT(4)
0098 #define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE
0099 
0100 #define PRM_ST_INTRANSITION BIT(20)
0101 
0102 static const struct omap_prm_domain_map omap_prm_all = {
0103     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
0104             BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
0105     .statechange = 1,
0106     .logicretstate = 1,
0107 };
0108 
0109 static const struct omap_prm_domain_map omap_prm_noinact = {
0110     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
0111             BIT(OMAP_PRMD_OFF),
0112     .statechange = 1,
0113     .logicretstate = 1,
0114 };
0115 
0116 static const struct omap_prm_domain_map omap_prm_nooff = {
0117     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
0118             BIT(OMAP_PRMD_RETENTION),
0119     .statechange = 1,
0120     .logicretstate = 1,
0121 };
0122 
0123 static const struct omap_prm_domain_map omap_prm_onoff_noauto = {
0124     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
0125     .statechange = 1,
0126 };
0127 
0128 static const struct omap_prm_domain_map omap_prm_alwon = {
0129     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE),
0130 };
0131 
0132 static const struct omap_prm_domain_map omap_prm_reton = {
0133     .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION),
0134     .statechange = 1,
0135     .logicretstate = 1,
0136 };
0137 
0138 static const struct omap_rst_map rst_map_0[] = {
0139     { .rst = 0, .st = 0 },
0140     { .rst = -1 },
0141 };
0142 
0143 static const struct omap_rst_map rst_map_01[] = {
0144     { .rst = 0, .st = 0 },
0145     { .rst = 1, .st = 1 },
0146     { .rst = -1 },
0147 };
0148 
0149 static const struct omap_rst_map rst_map_012[] = {
0150     { .rst = 0, .st = 0 },
0151     { .rst = 1, .st = 1 },
0152     { .rst = 2, .st = 2 },
0153     { .rst = -1 },
0154 };
0155 
0156 static const struct omap_prm_data omap4_prm_data[] = {
0157     {
0158         .name = "mpu", .base = 0x4a306300,
0159         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0160     },
0161     {
0162         .name = "tesla", .base = 0x4a306400,
0163         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0164         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0165     },
0166     {
0167         .name = "abe", .base = 0x4a306500,
0168         .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
0169     },
0170     {
0171         .name = "always_on_core", .base = 0x4a306600,
0172         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0173     },
0174     {
0175         .name = "core", .base = 0x4a306700,
0176         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0177         .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati",
0178         .rstmap = rst_map_012,
0179         .flags = OMAP_PRM_RET_WHEN_IDLE,
0180     },
0181     {
0182         .name = "ivahd", .base = 0x4a306f00,
0183         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0184         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
0185     },
0186     {
0187         .name = "cam", .base = 0x4a307000,
0188         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0189     },
0190     {
0191         .name = "dss", .base = 0x4a307100,
0192         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
0193     },
0194     {
0195         .name = "gfx", .base = 0x4a307200,
0196         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0197     },
0198     {
0199         .name = "l3init", .base = 0x4a307300,
0200         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
0201     },
0202     {
0203         .name = "l4per", .base = 0x4a307400,
0204         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0205         .flags = OMAP_PRM_RET_WHEN_IDLE,
0206     },
0207     {
0208         .name = "cefuse", .base = 0x4a307600,
0209         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0210     },
0211     {
0212         .name = "wkup", .base = 0x4a307700,
0213         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
0214     },
0215     {
0216         .name = "emu", .base = 0x4a307900,
0217         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0218     },
0219     {
0220         .name = "device", .base = 0x4a307b00,
0221         .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
0222         .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
0223     },
0224     { },
0225 };
0226 
0227 static const struct omap_prm_data omap5_prm_data[] = {
0228     {
0229         .name = "mpu", .base = 0x4ae06300,
0230         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0231     },
0232     {
0233         .name = "dsp", .base = 0x4ae06400,
0234         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0235         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0236     },
0237     {
0238         .name = "abe", .base = 0x4ae06500,
0239         .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff,
0240     },
0241     {
0242         .name = "coreaon", .base = 0x4ae06600,
0243         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
0244     },
0245     {
0246         .name = "core", .base = 0x4ae06700,
0247         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0248         .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu",
0249         .rstmap = rst_map_012
0250     },
0251     {
0252         .name = "iva", .base = 0x4ae07200,
0253         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0254         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
0255     },
0256     {
0257         .name = "cam", .base = 0x4ae07300,
0258         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0259     },
0260     {
0261         .name = "dss", .base = 0x4ae07400,
0262         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact
0263     },
0264     {
0265         .name = "gpu", .base = 0x4ae07500,
0266         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0267     },
0268     {
0269         .name = "l3init", .base = 0x4ae07600,
0270         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton
0271     },
0272     {
0273         .name = "custefuse", .base = 0x4ae07700,
0274         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0275     },
0276     {
0277         .name = "wkupaon", .base = 0x4ae07800,
0278         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon
0279     },
0280     {
0281         .name = "emu", .base = 0x4ae07a00,
0282         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto
0283     },
0284     {
0285         .name = "device", .base = 0x4ae07c00,
0286         .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01,
0287         .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
0288     },
0289     { },
0290 };
0291 
0292 static const struct omap_prm_data dra7_prm_data[] = {
0293     {
0294         .name = "mpu", .base = 0x4ae06300,
0295         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
0296     },
0297     {
0298         .name = "dsp1", .base = 0x4ae06400,
0299         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0300         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
0301     },
0302     {
0303         .name = "ipu", .base = 0x4ae06500,
0304         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0305         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
0306         .clkdm_name = "ipu1"
0307     },
0308     {
0309         .name = "coreaon", .base = 0x4ae06628,
0310         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0311     },
0312     {
0313         .name = "core", .base = 0x4ae06700,
0314         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0315         .rstctrl = 0x210, .rstst = 0x214, .rstmap = rst_map_012,
0316         .clkdm_name = "ipu2"
0317     },
0318     {
0319         .name = "iva", .base = 0x4ae06f00,
0320         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0321         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012,
0322     },
0323     {
0324         .name = "cam", .base = 0x4ae07000,
0325         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0326     },
0327     {
0328         .name = "dss", .base = 0x4ae07100,
0329         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0330     },
0331     {
0332         .name = "gpu", .base = 0x4ae07200,
0333         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0334     },
0335     {
0336         .name = "l3init", .base = 0x4ae07300,
0337         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0338         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01,
0339         .clkdm_name = "pcie"
0340     },
0341     {
0342         .name = "l4per", .base = 0x4ae07400,
0343         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0344     },
0345     {
0346         .name = "custefuse", .base = 0x4ae07600,
0347         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0348     },
0349     {
0350         .name = "wkupaon", .base = 0x4ae07724,
0351         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0352     },
0353     {
0354         .name = "emu", .base = 0x4ae07900,
0355         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0356     },
0357     {
0358         .name = "dsp2", .base = 0x4ae07b00,
0359         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0360         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0361     },
0362     {
0363         .name = "eve1", .base = 0x4ae07b40,
0364         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0365         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0366     },
0367     {
0368         .name = "eve2", .base = 0x4ae07b80,
0369         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0370         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0371     },
0372     {
0373         .name = "eve3", .base = 0x4ae07bc0,
0374         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0375         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0376     },
0377     {
0378         .name = "eve4", .base = 0x4ae07c00,
0379         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0380         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
0381     },
0382     {
0383         .name = "rtc", .base = 0x4ae07c60,
0384         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0385     },
0386     {
0387         .name = "vpe", .base = 0x4ae07c80,
0388         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0389     },
0390     { },
0391 };
0392 
0393 static const struct omap_rst_map am3_per_rst_map[] = {
0394     { .rst = 1 },
0395     { .rst = -1 },
0396 };
0397 
0398 static const struct omap_rst_map am3_wkup_rst_map[] = {
0399     { .rst = 3, .st = 5 },
0400     { .rst = -1 },
0401 };
0402 
0403 static const struct omap_prm_data am3_prm_data[] = {
0404     {
0405         .name = "per", .base = 0x44e00c00,
0406         .pwrstctrl = 0xc, .pwrstst = 0x8, .dmap = &omap_prm_noinact,
0407         .rstctrl = 0x0, .rstmap = am3_per_rst_map,
0408         .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp"
0409     },
0410     {
0411         .name = "wkup", .base = 0x44e00d00,
0412         .pwrstctrl = 0x4, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0413         .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map,
0414         .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
0415     },
0416     {
0417         .name = "mpu", .base = 0x44e00e00,
0418         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0419     },
0420     {
0421         .name = "device", .base = 0x44e00f00,
0422         .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01,
0423         .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
0424     },
0425     {
0426         .name = "rtc", .base = 0x44e01000,
0427         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0428     },
0429     {
0430         .name = "gfx", .base = 0x44e01100,
0431         .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact,
0432         .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
0433     },
0434     {
0435         .name = "cefuse", .base = 0x44e01200,
0436         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0437     },
0438     { },
0439 };
0440 
0441 static const struct omap_rst_map am4_per_rst_map[] = {
0442     { .rst = 1, .st = 0 },
0443     { .rst = -1 },
0444 };
0445 
0446 static const struct omap_rst_map am4_device_rst_map[] = {
0447     { .rst = 0, .st = 1 },
0448     { .rst = 1, .st = 0 },
0449     { .rst = -1 },
0450 };
0451 
0452 static const struct omap_prm_data am4_prm_data[] = {
0453     {
0454         .name = "mpu", .base = 0x44df0300,
0455         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0456     },
0457     {
0458         .name = "gfx", .base = 0x44df0400,
0459         .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0460         .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3",
0461     },
0462     {
0463         .name = "rtc", .base = 0x44df0500,
0464         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0465     },
0466     {
0467         .name = "tamper", .base = 0x44df0600,
0468         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0469     },
0470     {
0471         .name = "cefuse", .base = 0x44df0700,
0472         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
0473     },
0474     {
0475         .name = "per", .base = 0x44df0800,
0476         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
0477         .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map,
0478         .clkdm_name = "pruss_ocp"
0479     },
0480     {
0481         .name = "wkup", .base = 0x44df2000,
0482         .pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
0483         .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map,
0484         .flags = OMAP_PRM_HAS_NO_CLKDM
0485     },
0486     {
0487         .name = "device", .base = 0x44df4000,
0488         .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map,
0489         .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM
0490     },
0491     { },
0492 };
0493 
0494 static const struct of_device_id omap_prm_id_table[] = {
0495     { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data },
0496     { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data },
0497     { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data },
0498     { .compatible = "ti,am3-prm-inst", .data = am3_prm_data },
0499     { .compatible = "ti,am4-prm-inst", .data = am4_prm_data },
0500     { },
0501 };
0502 
0503 #ifdef DEBUG
0504 static void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
0505                        const char *desc)
0506 {
0507     dev_dbg(prmd->dev, "%s %s: %08x/%08x\n",
0508         prmd->pd.name, desc,
0509         readl_relaxed(prmd->prm->base + prmd->pwrstctrl),
0510         readl_relaxed(prmd->prm->base + prmd->pwrstst));
0511 }
0512 #else
0513 static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd,
0514                           const char *desc)
0515 {
0516 }
0517 #endif
0518 
0519 static int omap_prm_domain_power_on(struct generic_pm_domain *domain)
0520 {
0521     struct omap_prm_domain *prmd;
0522     int ret;
0523     u32 v, mode;
0524 
0525     prmd = genpd_to_prm_domain(domain);
0526     if (!prmd->cap)
0527         return 0;
0528 
0529     omap_prm_domain_show_state(prmd, "on: previous state");
0530 
0531     if (prmd->pwrstctrl_saved)
0532         v = prmd->pwrstctrl_saved;
0533     else
0534         v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
0535 
0536     if (prmd->prm->data->flags & OMAP_PRM_RET_WHEN_IDLE)
0537         mode = OMAP_PRMD_RETENTION;
0538     else
0539         mode = OMAP_PRMD_ON_ACTIVE;
0540 
0541     writel_relaxed((v & ~PRM_POWERSTATE_MASK) | mode,
0542                prmd->prm->base + prmd->pwrstctrl);
0543 
0544     /* wait for the transition bit to get cleared */
0545     ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
0546                      v, !(v & PRM_ST_INTRANSITION), 1,
0547                      PRM_STATE_MAX_WAIT);
0548     if (ret)
0549         dev_err(prmd->dev, "%s: %s timed out\n",
0550             prmd->pd.name, __func__);
0551 
0552     omap_prm_domain_show_state(prmd, "on: new state");
0553 
0554     return ret;
0555 }
0556 
0557 /* No need to check for holes in the mask for the lowest mode */
0558 static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd)
0559 {
0560     return __ffs(prmd->cap->usable_modes);
0561 }
0562 
0563 static int omap_prm_domain_power_off(struct generic_pm_domain *domain)
0564 {
0565     struct omap_prm_domain *prmd;
0566     int ret;
0567     u32 v;
0568 
0569     prmd = genpd_to_prm_domain(domain);
0570     if (!prmd->cap)
0571         return 0;
0572 
0573     omap_prm_domain_show_state(prmd, "off: previous state");
0574 
0575     v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl);
0576     prmd->pwrstctrl_saved = v;
0577 
0578     v &= ~PRM_POWERSTATE_MASK;
0579     v |= omap_prm_domain_find_lowest(prmd);
0580 
0581     if (prmd->cap->statechange)
0582         v |= PRM_LOWPOWERSTATECHANGE;
0583     if (prmd->cap->logicretstate)
0584         v &= ~PRM_LOGICRETSTATE;
0585     else
0586         v |= PRM_LOGICRETSTATE;
0587 
0588     writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl);
0589 
0590     /* wait for the transition bit to get cleared */
0591     ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst,
0592                      v, !(v & PRM_ST_INTRANSITION), 1,
0593                      PRM_STATE_MAX_WAIT);
0594     if (ret)
0595         dev_warn(prmd->dev, "%s: %s timed out\n",
0596              __func__, prmd->pd.name);
0597 
0598     omap_prm_domain_show_state(prmd, "off: new state");
0599 
0600     return 0;
0601 }
0602 
0603 /*
0604  * Note that ti-sysc already manages the module clocks separately so
0605  * no need to manage those. Interconnect instances need clocks managed
0606  * for simple-pm-bus.
0607  */
0608 static int omap_prm_domain_attach_clock(struct device *dev,
0609                     struct omap_prm_domain *prmd)
0610 {
0611     struct device_node *np = dev->of_node;
0612     int error;
0613 
0614     if (!of_device_is_compatible(np, "simple-pm-bus"))
0615         return 0;
0616 
0617     if (!of_property_read_bool(np, "clocks"))
0618         return 0;
0619 
0620     error = pm_clk_create(dev);
0621     if (error)
0622         return error;
0623 
0624     error = of_pm_clk_add_clks(dev);
0625     if (error < 0) {
0626         pm_clk_destroy(dev);
0627         return error;
0628     }
0629 
0630     prmd->uses_pm_clk = 1;
0631 
0632     return 0;
0633 }
0634 
0635 static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain,
0636                       struct device *dev)
0637 {
0638     struct generic_pm_domain_data *genpd_data;
0639     struct of_phandle_args pd_args;
0640     struct omap_prm_domain *prmd;
0641     struct device_node *np;
0642     int ret;
0643 
0644     prmd = genpd_to_prm_domain(domain);
0645     np = dev->of_node;
0646 
0647     ret = of_parse_phandle_with_args(np, "power-domains",
0648                      "#power-domain-cells", 0, &pd_args);
0649     if (ret < 0)
0650         return ret;
0651 
0652     if (pd_args.args_count != 0)
0653         dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n",
0654              prmd->pd.name, pd_args.args_count);
0655 
0656     genpd_data = dev_gpd_data(dev);
0657     genpd_data->data = NULL;
0658 
0659     ret = omap_prm_domain_attach_clock(dev, prmd);
0660     if (ret)
0661         return ret;
0662 
0663     return 0;
0664 }
0665 
0666 static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain,
0667                        struct device *dev)
0668 {
0669     struct generic_pm_domain_data *genpd_data;
0670     struct omap_prm_domain *prmd;
0671 
0672     prmd = genpd_to_prm_domain(domain);
0673     if (prmd->uses_pm_clk)
0674         pm_clk_destroy(dev);
0675     genpd_data = dev_gpd_data(dev);
0676     genpd_data->data = NULL;
0677 }
0678 
0679 static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm)
0680 {
0681     struct omap_prm_domain *prmd;
0682     struct device_node *np = dev->of_node;
0683     const struct omap_prm_data *data;
0684     const char *name;
0685     int error;
0686 
0687     if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
0688         return 0;
0689 
0690     of_node_put(dev->of_node);
0691 
0692     prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL);
0693     if (!prmd)
0694         return -ENOMEM;
0695 
0696     data = prm->data;
0697     name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s",
0698                   data->name);
0699 
0700     prmd->dev = dev;
0701     prmd->prm = prm;
0702     prmd->cap = prmd->prm->data->dmap;
0703     prmd->pwrstctrl = prmd->prm->data->pwrstctrl;
0704     prmd->pwrstst = prmd->prm->data->pwrstst;
0705 
0706     prmd->pd.name = name;
0707     prmd->pd.power_on = omap_prm_domain_power_on;
0708     prmd->pd.power_off = omap_prm_domain_power_off;
0709     prmd->pd.attach_dev = omap_prm_domain_attach_dev;
0710     prmd->pd.detach_dev = omap_prm_domain_detach_dev;
0711     prmd->pd.flags = GENPD_FLAG_PM_CLK;
0712 
0713     pm_genpd_init(&prmd->pd, NULL, true);
0714     error = of_genpd_add_provider_simple(np, &prmd->pd);
0715     if (error)
0716         pm_genpd_remove(&prmd->pd);
0717     else
0718         prm->prmd = prmd;
0719 
0720     return error;
0721 }
0722 
0723 static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id)
0724 {
0725     if (reset->mask & BIT(id))
0726         return true;
0727 
0728     return false;
0729 }
0730 
0731 static int omap_reset_get_st_bit(struct omap_reset_data *reset,
0732                  unsigned long id)
0733 {
0734     const struct omap_rst_map *map = reset->prm->data->rstmap;
0735 
0736     while (map->rst >= 0) {
0737         if (map->rst == id)
0738             return map->st;
0739 
0740         map++;
0741     }
0742 
0743     return id;
0744 }
0745 
0746 static int omap_reset_status(struct reset_controller_dev *rcdev,
0747                  unsigned long id)
0748 {
0749     struct omap_reset_data *reset = to_omap_reset_data(rcdev);
0750     u32 v;
0751     int st_bit = omap_reset_get_st_bit(reset, id);
0752     bool has_rstst = reset->prm->data->rstst ||
0753         (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
0754 
0755     /* Check if we have rstst */
0756     if (!has_rstst)
0757         return -ENOTSUPP;
0758 
0759     /* Check if hw reset line is asserted */
0760     v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
0761     if (v & BIT(id))
0762         return 1;
0763 
0764     /*
0765      * Check reset status, high value means reset sequence has been
0766      * completed successfully so we can return 0 here (reset deasserted)
0767      */
0768     v = readl_relaxed(reset->prm->base + reset->prm->data->rstst);
0769     v >>= st_bit;
0770     v &= 1;
0771 
0772     return !v;
0773 }
0774 
0775 static int omap_reset_assert(struct reset_controller_dev *rcdev,
0776                  unsigned long id)
0777 {
0778     struct omap_reset_data *reset = to_omap_reset_data(rcdev);
0779     u32 v;
0780     unsigned long flags;
0781 
0782     /* assert the reset control line */
0783     spin_lock_irqsave(&reset->lock, flags);
0784     v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
0785     v |= 1 << id;
0786     writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
0787     spin_unlock_irqrestore(&reset->lock, flags);
0788 
0789     return 0;
0790 }
0791 
0792 static int omap_reset_deassert(struct reset_controller_dev *rcdev,
0793                    unsigned long id)
0794 {
0795     struct omap_reset_data *reset = to_omap_reset_data(rcdev);
0796     u32 v;
0797     int st_bit;
0798     bool has_rstst;
0799     unsigned long flags;
0800     struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev);
0801     int ret = 0;
0802 
0803     /* Nothing to do if the reset is already deasserted */
0804     if (!omap_reset_status(rcdev, id))
0805         return 0;
0806 
0807     has_rstst = reset->prm->data->rstst ||
0808         (reset->prm->data->flags & OMAP_PRM_HAS_RSTST);
0809 
0810     if (has_rstst) {
0811         st_bit = omap_reset_get_st_bit(reset, id);
0812 
0813         /* Clear the reset status by writing 1 to the status bit */
0814         v = 1 << st_bit;
0815         writel_relaxed(v, reset->prm->base + reset->prm->data->rstst);
0816     }
0817 
0818     if (reset->clkdm)
0819         pdata->clkdm_deny_idle(reset->clkdm);
0820 
0821     /* de-assert the reset control line */
0822     spin_lock_irqsave(&reset->lock, flags);
0823     v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
0824     v &= ~(1 << id);
0825     writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl);
0826     spin_unlock_irqrestore(&reset->lock, flags);
0827 
0828     /* wait for the reset bit to clear */
0829     ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
0830                         reset->prm->data->rstctrl,
0831                         v, !(v & BIT(id)), 1,
0832                         OMAP_RESET_MAX_WAIT);
0833     if (ret)
0834         pr_err("%s: timedout waiting for %s:%lu\n", __func__,
0835                reset->prm->data->name, id);
0836 
0837     /* wait for the status to be set */
0838     if (has_rstst) {
0839         ret = readl_relaxed_poll_timeout_atomic(reset->prm->base +
0840                          reset->prm->data->rstst,
0841                          v, v & BIT(st_bit), 1,
0842                          OMAP_RESET_MAX_WAIT);
0843         if (ret)
0844             pr_err("%s: timedout waiting for %s:%lu\n", __func__,
0845                    reset->prm->data->name, id);
0846     }
0847 
0848     if (reset->clkdm)
0849         pdata->clkdm_allow_idle(reset->clkdm);
0850 
0851     return ret;
0852 }
0853 
0854 static const struct reset_control_ops omap_reset_ops = {
0855     .assert     = omap_reset_assert,
0856     .deassert   = omap_reset_deassert,
0857     .status     = omap_reset_status,
0858 };
0859 
0860 static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev,
0861                 const struct of_phandle_args *reset_spec)
0862 {
0863     struct omap_reset_data *reset = to_omap_reset_data(rcdev);
0864 
0865     if (!_is_valid_reset(reset, reset_spec->args[0]))
0866         return -EINVAL;
0867 
0868     return reset_spec->args[0];
0869 }
0870 
0871 static int omap_prm_reset_init(struct platform_device *pdev,
0872                    struct omap_prm *prm)
0873 {
0874     struct omap_reset_data *reset;
0875     const struct omap_rst_map *map;
0876     struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev);
0877     char buf[32];
0878     u32 v;
0879 
0880     /*
0881      * Check if we have controllable resets. If either rstctrl is non-zero
0882      * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
0883      * for the domain.
0884      */
0885     if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL))
0886         return 0;
0887 
0888     /* Check if we have the pdata callbacks in place */
0889     if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle ||
0890         !pdata->clkdm_allow_idle)
0891         return -EINVAL;
0892 
0893     map = prm->data->rstmap;
0894     if (!map)
0895         return -EINVAL;
0896 
0897     reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL);
0898     if (!reset)
0899         return -ENOMEM;
0900 
0901     reset->rcdev.owner = THIS_MODULE;
0902     reset->rcdev.ops = &omap_reset_ops;
0903     reset->rcdev.of_node = pdev->dev.of_node;
0904     reset->rcdev.nr_resets = OMAP_MAX_RESETS;
0905     reset->rcdev.of_xlate = omap_prm_reset_xlate;
0906     reset->rcdev.of_reset_n_cells = 1;
0907     reset->dev = &pdev->dev;
0908     spin_lock_init(&reset->lock);
0909 
0910     reset->prm = prm;
0911 
0912     sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name :
0913         prm->data->name);
0914 
0915     if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) {
0916         reset->clkdm = pdata->clkdm_lookup(buf);
0917         if (!reset->clkdm)
0918             return -EINVAL;
0919     }
0920 
0921     while (map->rst >= 0) {
0922         reset->mask |= BIT(map->rst);
0923         map++;
0924     }
0925 
0926     /* Quirk handling to assert rst_map_012 bits on reset and avoid errors */
0927     if (prm->data->rstmap == rst_map_012) {
0928         v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl);
0929         if ((v & reset->mask) != reset->mask) {
0930             dev_dbg(&pdev->dev, "Asserting all resets: %08x\n", v);
0931             writel_relaxed(reset->mask, reset->prm->base +
0932                        reset->prm->data->rstctrl);
0933         }
0934     }
0935 
0936     return devm_reset_controller_register(&pdev->dev, &reset->rcdev);
0937 }
0938 
0939 static int omap_prm_probe(struct platform_device *pdev)
0940 {
0941     struct resource *res;
0942     const struct omap_prm_data *data;
0943     struct omap_prm *prm;
0944     int ret;
0945 
0946     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0947     if (!res)
0948         return -ENODEV;
0949 
0950     data = of_device_get_match_data(&pdev->dev);
0951     if (!data)
0952         return -ENOTSUPP;
0953 
0954     prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL);
0955     if (!prm)
0956         return -ENOMEM;
0957 
0958     while (data->base != res->start) {
0959         if (!data->base)
0960             return -EINVAL;
0961         data++;
0962     }
0963 
0964     prm->data = data;
0965 
0966     prm->base = devm_ioremap_resource(&pdev->dev, res);
0967     if (IS_ERR(prm->base))
0968         return PTR_ERR(prm->base);
0969 
0970     ret = omap_prm_domain_init(&pdev->dev, prm);
0971     if (ret)
0972         return ret;
0973 
0974     ret = omap_prm_reset_init(pdev, prm);
0975     if (ret)
0976         goto err_domain;
0977 
0978     return 0;
0979 
0980 err_domain:
0981     of_genpd_del_provider(pdev->dev.of_node);
0982     pm_genpd_remove(&prm->prmd->pd);
0983 
0984     return ret;
0985 }
0986 
0987 static struct platform_driver omap_prm_driver = {
0988     .probe = omap_prm_probe,
0989     .driver = {
0990         .name       = KBUILD_MODNAME,
0991         .of_match_table = omap_prm_id_table,
0992     },
0993 };
0994 builtin_platform_driver(omap_prm_driver);