// SPDX-License-Identifier: GPL-2.0
/*
* OMAP2+ PRM driver
*
* Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
* Tero Kristo <t-kristo@ti.com>
*/
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/reset-controller.h>
#include <linux/delay.h>
#include <linux/platform_data/ti-prm.h>
enum omap_prm_domain_mode {
OMAP_PRMD_OFF,
OMAP_PRMD_RETENTION,
OMAP_PRMD_ON_INACTIVE,
OMAP_PRMD_ON_ACTIVE,
};
struct omap_prm_domain_map {
unsigned int usable_modes; /* Mask of hardware supported modes */
unsigned long statechange:1; /* Optional low-power state change */
unsigned long logicretstate:1; /* Optional logic off mode */
};
struct omap_prm_domain {
struct device *dev;
struct omap_prm *prm;
struct generic_pm_domain pd;
u16 pwrstctrl;
u16 pwrstst;
const struct omap_prm_domain_map *cap;
u32 pwrstctrl_saved;
unsigned int uses_pm_clk:1;
};
struct omap_rst_map {
s8 rst;
s8 st;
};
struct omap_prm_data {
u32 base;
const char *name;
const char *clkdm_name;
u16 pwrstctrl;
u16 pwrstst;
const struct omap_prm_domain_map *dmap;
u16 rstctrl;
u16 rstst;
const struct omap_rst_map *rstmap;
u8 flags;
};
struct omap_prm {
const struct omap_prm_data *data;
void __iomem *base;
struct omap_prm_domain *prmd;
};
struct omap_reset_data {
struct reset_controller_dev rcdev;
struct omap_prm *prm;
u32 mask;
spinlock_t lock;
struct clockdomain *clkdm;
struct device *dev;
};
#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd)
#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
#define OMAP_MAX_RESETS 8
#define OMAP_RESET_MAX_WAIT 10000
#define OMAP_PRM_HAS_RSTCTRL BIT(0)
#define OMAP_PRM_HAS_RSTST BIT(1)
#define OMAP_PRM_HAS_NO_CLKDM BIT(2)
#define OMAP_PRM_RET_WHEN_IDLE BIT(3)
#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
#define PRM_STATE_MAX_WAIT 10000
#define PRM_LOGICRETSTATE BIT(2)
#define PRM_LOWPOWERSTATECHANGE BIT(4)
#define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE
#define PRM_ST_INTRANSITION BIT(20)
static const struct omap_prm_domain_map omap_prm_all = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF),
.statechange = 1,
.logicretstate = 1,
};
static const struct omap_prm_domain_map omap_prm_noinact = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) |
BIT(OMAP_PRMD_OFF),
.statechange = 1,
.logicretstate = 1,
};
static const struct omap_prm_domain_map omap_prm_nooff = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) |
BIT(OMAP_PRMD_RETENTION),
.statechange = 1,
.logicretstate = 1,
};
static const struct omap_prm_domain_map omap_prm_onoff_noauto = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF),
.statechange = 1,
};
static const struct omap_prm_domain_map omap_prm_alwon = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE),
};
static const struct omap_prm_domain_map omap_prm_reton = {
.usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION),
.statechange = 1,
.logicretstate = 1,
};
static const struct omap_rst_map rst_map_0[] = {
{ .rst = 0, .st = 0 },
{ .rst = -1 },
};
static const struct omap_rst_map rst_map_01[] = {
{ .rst = 0, .st = 0 },
{ .rst = 1, .st = 1 },
{ .rst = -1 },
};
static const struct omap_rst_map rst_map_012[] = {
{ .rst = 0, .st = 0 },
{ .rst = 1, .st = 1 },
{ .rst = 2, .st = 2 },
{ .rst = -1 },
};
static const struct omap_prm_data omap4_prm_data[] = {
{
.name = "mpu", .base = 0x4a306300,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
},
{
.name = "tesla", .base = 0x4a306400,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01
},
{
.name = "abe", .base = 0x4a306500,
.pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all,
},
{
.name = "always_on_core", .base = 0x4a306600,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_alwon,
},
{
.name = "core", .base = 0x4a306700,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_reton,
.rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati",
.rstmap = rst_map_012,
.flags = OMAP_PRM_RET_WHEN_IDLE,
},
{
.name = "ivahd", .base = 0x4a306f00,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_noinact,
.rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012
},
{
.name = "cam", .base = 0x4a307000,
.pwrstctrl = 0x0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto,
},
{
.name = "dss",