// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
#include <linux/atomic.h>
#include <linux/cpu_pm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <clocksource/arm_arch_timer.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/tcs.h>
#include <dt-bindings/soc/qcom,rpmh-rsc.h>
#include "rpmh-internal.h"
#define CREATE_TRACE_POINTS
#include "trace-rpmh.h"
#define RSC_DRV_ID 0
#define MAJOR_VER_MASK 0xFF
#define MAJOR_VER_SHIFT 16
#define MINOR_VER_MASK 0xFF
#define MINOR_VER_SHIFT 8
enum {
RSC_DRV_TCS_OFFSET,
RSC_DRV_CMD_OFFSET,
DRV_SOLVER_CONFIG,
DRV_PRNT_CHLD_CONFIG,
RSC_DRV_IRQ_ENABLE,
RSC_DRV_IRQ_STATUS,
RSC_DRV_IRQ_CLEAR,
RSC_DRV_CMD_WAIT_FOR_CMPL,
RSC_DRV_CONTROL,
RSC_DRV_STATUS,
RSC_DRV_CMD_ENABLE,
RSC_DRV_CMD_MSGID,
RSC_DRV_CMD_ADDR,
RSC_DRV_CMD_DATA,
RSC_DRV_CMD_STATUS,
RSC_DRV_CMD_RESP_DATA,
};
/* DRV HW Solver Configuration Information Register */
#define DRV_HW_SOLVER_MASK 1
#define DRV_HW_SOLVER_SHIFT 24
/* DRV TCS Configuration Information Register */
#define DRV_NUM_TCS_MASK 0x3F
#define DRV_NUM_TCS_SHIFT 6
#define DRV_NCPT_MASK 0x1F
#define DRV_NCPT_SHIFT 27
/* Offsets for CONTROL TCS Registers */
#define RSC_DRV_CTL_TCS_DATA_HI 0x38
#define RSC_DRV_CTL_TCS_DATA_HI_MASK 0xFFFFFF
#define RSC_DRV_CTL_TCS_DATA_HI_VALID BIT(31)
#define RSC_DRV_CTL_TCS_DATA_LO 0x40
#define RSC_DRV_CTL_TCS_DATA_LO_MASK 0xFFFFFFFF
#define RSC_DRV_CTL_TCS_DATA_SIZE 32
#define TCS_AMC_MODE_ENABLE BIT(16)
#define TCS_AMC_MODE_TRIGGER BIT(24)
/* TCS CMD register bit mask */
#define CMD_MSGID_LEN 8
#define CMD_MSGID_RESP_REQ BIT(8)
#define CMD_MSGID_WRITE BIT(16)
#define CMD_STATUS_ISSUED BIT(8)
#define CMD_STATUS_COMPL BIT(16)
/*
* Here's a high level overview of how all the registers in RPMH work
* together:
*
* - The main rpmh-rsc address is the base of a register space that can
* be used to find overall configuration of the hardware
* (DRV_PRNT_CHLD_CONFIG). Also found within the rpmh-rsc register
* space are all the TCS blocks. The offset of the TCS blocks is
* specified in the device tree by "qcom,tcs-offset" and used to
* compute tcs_base.
* - TCS blocks come one after another. Type, count, and order are
* specified by the device tree as "qcom,tcs-config".
* - Each TCS block has some registers, then space for up to 16 commands.
* Note that though address space is reserved for 16 commands, fewer
* might be present. See ncpt (num cmds per TCS).
*
* Here's a picture:
*
* +---------------------------------------------------+
* |RSC |
* | ctrl |
* | |
* | Drvs: |
* | +-----------------------------------------------+ |
* | |DRV0 | |
* | | ctrl/config | |
* | | IRQ | |
* | | | |
* | | TCSes: | |
* | | +------------------------------------------+ | |
* | | |TCS0 | | | | | | | | | | | | | | |
* | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15| | |
* | | | | | | | | | | | | | | | | | |
* | | +------------------------------------------+ | |
* | | +------------------------------------------+ | |
* | | |TCS1 | | | | | | | | | | | | | | |
* | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15| | |
* | | | | | | | | | | | | | | | | | |
* | | +------------------------------------------+ | |
* | | +------------------------------------------+ | |
* | | |TCS2 | | | | | | | | | | | | | | |
* | | | ctrl | 0| 1| 2| 3| 4| 5| .| .| .| .|14|15| | |
* | | | | | | | | | | | | | | | | | |
* | | +------------------------------------------+ | |
* | | ...... | |
* | +-----------------------------------------------+ |
* | +-----------------------------------------------+ |
* | |DRV1 | |
* | | (same as DRV0) | |
* | +-----------------------------------------------+ |
* | ...... |
* +---------------------------------------------------+
*/
#define USECS_TO_CYCLES(time_usecs) \
xloops_to_cycles((time_usecs) * 0x10C7UL)
static inline unsigned long xloops_to_cycles(u64 xloops)
{
return (xloops * loops_per_jiffy * HZ) >> 32;
}
static u32 rpmh_rsc_reg_offset_ver_2_7[] = {
[RSC_DRV_TCS_OFFSET] = 672,
[RSC_DRV_CMD_OFFSET] = 20,
[DRV_SOLVER_CONFIG] = 0x04,
[DRV_PRNT_CHLD_CONFIG] = 0x0C,
[RSC_DRV_IRQ_ENABLE] = 0x00,
[RSC_DRV_IRQ_STATUS] = 0x04,
[RSC_DRV_IRQ_CLEAR] = 0x08,
[RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x10,
[RSC_DRV_CONTROL] = 0x14,
[RSC_DRV_STATUS] = 0x18,
[RSC_DRV_CMD_ENABLE] = 0x1C,
[RSC_DRV_CMD_MSGID] = 0x30,
[RSC_DRV_CMD_ADDR] = 0x34,
[RSC_DRV_CMD_DATA] = 0x38,
[RSC_DRV_CMD_STATUS] = 0x3C,
[RSC_DRV_CMD_RESP_DATA] = 0x40,
};
static u32 rpmh_rsc_reg_offset_ver_3_0[] = {
[RSC_DRV_TCS_OFFSET] = 672,
[RSC_DRV_CMD_OFFSET] = 24,
[DRV_SOLVER_CONFIG] = 0x04,
[DRV_PRNT_CHLD_CONFIG] = 0x0C,
[RSC_DRV_IRQ_ENABLE] = 0x00,
[RSC_DRV_IRQ_STATUS] = 0x04,
[RSC_DRV_IRQ_CLEAR] = 0x08,
[RSC_DRV_CMD_WAIT_FOR_CMPL] = 0x20,
[RSC_DRV_CONTROL] = 0x24,
[RSC_DRV_STATUS] = 0x28,
[RSC_DRV_CMD_ENABLE] = 0x2C,
[RSC_DRV_CMD_MSGID] = 0x34,
[RSC_DRV_CMD_ADDR] = 0x38,
[RSC_DRV_CMD_DATA] = 0x3C,
[RSC_DRV_CMD_STATUS] = 0x40,
[RSC_DRV_CMD_RESP_DATA] = 0x44,
};
static inline void __iomem *
tcs_reg_addr(