// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/pm_domain.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/soc/qcom/smd-rpm.h>
#include <dt-bindings/power/qcom-rpmpd.h>
#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
static struct qcom_smd_rpm *rpmpd_smd_rpm;
/* Resource types:
* RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
#define RPMPD_SMPA 0x61706d73
#define RPMPD_LDOA 0x616f646c
#define RPMPD_SMPB 0x62706d73
#define RPMPD_LDOB 0x626f646c
#define RPMPD_RWCX 0x78637772
#define RPMPD_RWMX 0x786d7772
#define RPMPD_RWLC 0x636c7772
#define RPMPD_RWLM 0x6d6c7772
#define RPMPD_RWSC 0x63737772
#define RPMPD_RWSM 0x6d737772
#define RPMPD_RWGX 0x78677772
/* Operation Keys */
#define KEY_CORNER 0x6e726f63 /* corn */
#define KEY_ENABLE 0x6e657773 /* swen */
#define KEY_FLOOR_CORNER 0x636676 /* vfc */
#define KEY_FLOOR_LEVEL 0x6c6676 /* vfl */
#define KEY_LEVEL 0x6c766c76 /* vlvl */
#define MAX_CORNER_RPMPD_STATE 6
struct rpmpd_req {
__le32 key;
__le32 nbytes;
__le32 value;
};
struct rpmpd {
struct generic_pm_domain pd;
struct generic_pm_domain *parent;
struct rpmpd *peer;
const bool active_only;
unsigned int corner;
bool enabled;
const int res_type;
const int res_id;
unsigned int max_state;
__le32 key;
bool state_synced;
};
struct rpmpd_desc {
struct rpmpd **rpmpds;
size_t num_pds;
unsigned int max_state;
};
static DEFINE_MUTEX(rpmpd_lock);
/* CX */
static struct rpmpd cx_rwcx0_lvl_ao;
static struct rpmpd cx_rwcx0_lvl = {
.pd = { .name = "cx", },
.peer = &cx_rwcx0_lvl_ao,
.res_type = RPMPD_RWCX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd cx_rwcx0_lvl_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_rwcx0_lvl,
.active_only = true,
.res_type = RPMPD_RWCX,
.res_id = 0,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s1a_corner_ao;
static struct rpmpd cx_s1a_corner = {
.pd = { .name = "cx", },
.peer = &cx_s1a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd cx_s1a_corner_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s1a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_CORNER,
};
static struct rpmpd cx_s1a_lvl_ao;
static struct rpmpd cx_s1a_lvl = {
.pd = { .name = "cx", },
.peer = &cx_s1a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s1a_lvl_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s1a_lvl,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 1,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s2a_corner_ao;
static struct rpmpd cx_s2a_corner = {
.pd = { .name = "cx", },
.peer = &cx_s2a_corner_ao,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2a_corner_ao = {
.pd = { .name = "cx_ao", },
.peer = &cx_s2a_corner,
.active_only = true,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_CORNER,
};
static struct rpmpd cx_s2a_lvl_ao;
static struct rpmpd cx_s2a_lvl = {
.pd = { .name = "cx", },
.peer = &cx_s2a_lvl_ao,
.res_type = RPMPD_SMPA,
.res_id = 2,
.key = KEY_LEVEL,
};
static struct rpmpd cx_s2a_lvl_ao =<