* [PATCH v6 01/24] dm: core: scan reserved-memory nodes
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 11:39 ` Simon Glass
2024-07-15 10:08 ` [PATCH v6 02/24] linux/bitmap.h: add bitmap_empty helper Caleb Connolly
` (23 subsequent siblings)
24 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Qualcomm platforms may have drivers that bind to reserved memory nodes
(cmd-db [1] and smem [2]) which are relevant to U-Boot. Include
/reserved-memory in dm_extended_scan() so that these will be handled
correctly.
[1]: https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/qcom%2Ccmd-db.yaml
[2]: https://www.kernel.org/doc/Documentation/devicetree/bindings/soc/qcom/qcom%2Csmem.yaml
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
To: Simon Glass <sjg@chromium.org>
---
drivers/core/root.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 7cf6607a9b7b..7a714f5478a9 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -242,9 +242,10 @@ int dm_extended_scan(bool pre_reloc_only)
int ret, i;
const char * const nodes[] = {
"/chosen",
"/clocks",
- "/firmware"
+ "/firmware",
+ "/reserved-memory",
};
ret = dm_scan_fdt(pre_reloc_only);
if (ret) {
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v6 01/24] dm: core: scan reserved-memory nodes
2024-07-15 10:08 ` [PATCH v6 01/24] dm: core: scan reserved-memory nodes Caleb Connolly
@ 2024-07-15 11:39 ` Simon Glass
0 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2024-07-15 11:39 UTC (permalink / raw)
To: Caleb Connolly
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
> Qualcomm platforms may have drivers that bind to reserved memory nodes
> (cmd-db [1] and smem [2]) which are relevant to U-Boot. Include
> /reserved-memory in dm_extended_scan() so that these will be handled
> correctly.
>
> [1]: https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/qcom%2Ccmd-db.yaml
> [2]: https://www.kernel.org/doc/Documentation/devicetree/bindings/soc/qcom/qcom%2Csmem.yaml
>
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
> To: Simon Glass <sjg@chromium.org>
> ---
> drivers/core/root.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
Reviewed-by: Simon Glass <sjg@chromium.org>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v6 02/24] linux/bitmap.h: add bitmap_empty helper
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 01/24] dm: core: scan reserved-memory nodes Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 03/24] soc: qcom: import rpmh and cmd-db drivers from Linux Caleb Connolly
` (22 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Import this function from Linux as of 6.10-rc6
Reviewed-by: Tom Rini <trini@konsulko.com>
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
include/linux/bitmap.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 0a8503af9f14..40ca2212cb40 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -195,8 +195,16 @@ static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
memset(dst, 0xff, len);
}
}
+static inline bool bitmap_empty(const unsigned long *src, unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return !(*src & BITMAP_LAST_WORD_MASK(nbits));
+
+ return find_first_bit(src, nbits) == nbits;
+}
+
static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
const unsigned long *src2, unsigned int nbits)
{
if (small_const_nbits(nbits))
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 03/24] soc: qcom: import rpmh and cmd-db drivers from Linux
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 01/24] dm: core: scan reserved-memory nodes Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 02/24] linux/bitmap.h: add bitmap_empty helper Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 04/24] soc: qcom: cmd-db: adjust headers for U-Boot Caleb Connolly
` (21 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Import RPMh and cmd-db framework from Linux 6.10-rc6.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/cmd-db.c | 393 +++++++++++++
drivers/soc/qcom/rpmh-internal.h | 148 +++++
drivers/soc/qcom/rpmh-rsc.c | 1162 ++++++++++++++++++++++++++++++++++++++
drivers/soc/qcom/rpmh.c | 502 ++++++++++++++++
include/soc/qcom/cmd-db.h | 48 ++
include/soc/qcom/rpmh.h | 47 ++
include/soc/qcom/tcs.h | 81 +++
7 files changed, 2381 insertions(+)
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
new file mode 100644
index 000000000000..d84572662017
--- /dev/null
+++ b/drivers/soc/qcom/cmd-db.c
@@ -0,0 +1,393 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+
+#include <soc/qcom/cmd-db.h>
+
+#define NUM_PRIORITY 2
+#define MAX_SLV_ID 8
+#define SLAVE_ID_MASK 0x7
+#define SLAVE_ID_SHIFT 16
+#define SLAVE_ID(addr) FIELD_GET(GENMASK(19, 16), addr)
+#define VRM_ADDR(addr) FIELD_GET(GENMASK(19, 4), addr)
+
+/**
+ * struct entry_header: header for each entry in cmddb
+ *
+ * @id: resource's identifier
+ * @priority: unused
+ * @addr: the address of the resource
+ * @len: length of the data
+ * @offset: offset from :@data_offset, start of the data
+ */
+struct entry_header {
+ u8 id[8];
+ __le32 priority[NUM_PRIORITY];
+ __le32 addr;
+ __le16 len;
+ __le16 offset;
+};
+
+/**
+ * struct rsc_hdr: resource header information
+ *
+ * @slv_id: id for the resource
+ * @header_offset: entry's header at offset from the end of the cmd_db_header
+ * @data_offset: entry's data at offset from the end of the cmd_db_header
+ * @cnt: number of entries for HW type
+ * @version: MSB is major, LSB is minor
+ * @reserved: reserved for future use.
+ */
+struct rsc_hdr {
+ __le16 slv_id;
+ __le16 header_offset;
+ __le16 data_offset;
+ __le16 cnt;
+ __le16 version;
+ __le16 reserved[3];
+};
+
+/**
+ * struct cmd_db_header: The DB header information
+ *
+ * @version: The cmd db version
+ * @magic: constant expected in the database
+ * @header: array of resources
+ * @checksum: checksum for the header. Unused.
+ * @reserved: reserved memory
+ * @data: driver specific data
+ */
+struct cmd_db_header {
+ __le32 version;
+ u8 magic[4];
+ struct rsc_hdr header[MAX_SLV_ID];
+ __le32 checksum;
+ __le32 reserved;
+ u8 data[];
+};
+
+/**
+ * DOC: Description of the Command DB database.
+ *
+ * At the start of the command DB memory is the cmd_db_header structure.
+ * The cmd_db_header holds the version, checksum, magic key as well as an
+ * array for header for each slave (depicted by the rsc_header). Each h/w
+ * based accelerator is a 'slave' (shared resource) and has slave id indicating
+ * the type of accelerator. The rsc_header is the header for such individual
+ * slaves of a given type. The entries for each of these slaves begin at the
+ * rsc_hdr.header_offset. In addition each slave could have auxiliary data
+ * that may be needed by the driver. The data for the slave starts at the
+ * entry_header.offset to the location pointed to by the rsc_hdr.data_offset.
+ *
+ * Drivers have a stringified key to a slave/resource. They can query the slave
+ * information and get the slave id and the auxiliary data and the length of the
+ * data. Using this information, they can format the request to be sent to the
+ * h/w accelerator and request a resource state.
+ */
+
+static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c };
+
+static bool cmd_db_magic_matches(const struct cmd_db_header *header)
+{
+ const u8 *magic = header->magic;
+
+ return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0;
+}
+
+static struct cmd_db_header *cmd_db_header;
+
+static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr)
+{
+ u16 offset = le16_to_cpu(hdr->header_offset);
+
+ return cmd_db_header->data + offset;
+}
+
+static inline void *
+rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent)
+{
+ u16 offset = le16_to_cpu(hdr->data_offset);
+ u16 loffset = le16_to_cpu(ent->offset);
+
+ return cmd_db_header->data + offset + loffset;
+}
+
+/**
+ * cmd_db_ready - Indicates if command DB is available
+ *
+ * Return: 0 on success, errno otherwise
+ */
+int cmd_db_ready(void)
+{
+ if (cmd_db_header == NULL)
+ return -EPROBE_DEFER;
+ else if (!cmd_db_magic_matches(cmd_db_header))
+ return -EINVAL;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cmd_db_ready);
+
+static int cmd_db_get_header(const char *id, const struct entry_header **eh,
+ const struct rsc_hdr **rh)
+{
+ const struct rsc_hdr *rsc_hdr;
+ const struct entry_header *ent;
+ int ret, i, j;
+ u8 query[sizeof(ent->id)] __nonstring;
+
+ ret = cmd_db_ready();
+ if (ret)
+ return ret;
+
+ strtomem_pad(query, id, 0);
+
+ for (i = 0; i < MAX_SLV_ID; i++) {
+ rsc_hdr = &cmd_db_header->header[i];
+ if (!rsc_hdr->slv_id)
+ break;
+
+ ent = rsc_to_entry_header(rsc_hdr);
+ for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) {
+ if (memcmp(ent->id, query, sizeof(ent->id)) == 0) {
+ if (eh)
+ *eh = ent;
+ if (rh)
+ *rh = rsc_hdr;
+ return 0;
+ }
+ }
+ }
+
+ return -ENODEV;
+}
+
+/**
+ * cmd_db_read_addr() - Query command db for resource id address.
+ *
+ * @id: resource id to query for address
+ *
+ * Return: resource address on success, 0 on error
+ *
+ * This is used to retrieve resource address based on resource
+ * id.
+ */
+u32 cmd_db_read_addr(const char *id)
+{
+ int ret;
+ const struct entry_header *ent;
+
+ ret = cmd_db_get_header(id, &ent, NULL);
+
+ return ret < 0 ? 0 : le32_to_cpu(ent->addr);
+}
+EXPORT_SYMBOL_GPL(cmd_db_read_addr);
+
+/**
+ * cmd_db_read_aux_data() - Query command db for aux data.
+ *
+ * @id: Resource to retrieve AUX Data on
+ * @len: size of data buffer returned
+ *
+ * Return: pointer to data on success, error pointer otherwise
+ */
+const void *cmd_db_read_aux_data(const char *id, size_t *len)
+{
+ int ret;
+ const struct entry_header *ent;
+ const struct rsc_hdr *rsc_hdr;
+
+ ret = cmd_db_get_header(id, &ent, &rsc_hdr);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (len)
+ *len = le16_to_cpu(ent->len);
+
+ return rsc_offset(rsc_hdr, ent);
+}
+EXPORT_SYMBOL_GPL(cmd_db_read_aux_data);
+
+/**
+ * cmd_db_match_resource_addr() - Compare if both Resource addresses are same
+ *
+ * @addr1: Resource address to compare
+ * @addr2: Resource address to compare
+ *
+ * Return: true if two addresses refer to the same resource, false otherwise
+ */
+bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
+{
+ /*
+ * Each RPMh VRM accelerator resource has 3 or 4 contiguous 4-byte
+ * aligned addresses associated with it. Ignore the offset to check
+ * for VRM requests.
+ */
+ if (addr1 == addr2)
+ return true;
+ else if (SLAVE_ID(addr1) == CMD_DB_HW_VRM && VRM_ADDR(addr1) == VRM_ADDR(addr2))
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(cmd_db_match_resource_addr);
+
+/**
+ * cmd_db_read_slave_id - Get the slave ID for a given resource address
+ *
+ * @id: Resource id to query the DB for version
+ *
+ * Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error
+ */
+enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
+{
+ int ret;
+ const struct entry_header *ent;
+ u32 addr;
+
+ ret = cmd_db_get_header(id, &ent, NULL);
+ if (ret < 0)
+ return CMD_DB_HW_INVALID;
+
+ addr = le32_to_cpu(ent->addr);
+ return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
+}
+EXPORT_SYMBOL_GPL(cmd_db_read_slave_id);
+
+#ifdef CONFIG_DEBUG_FS
+static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)
+{
+ int i, j;
+ const struct rsc_hdr *rsc;
+ const struct entry_header *ent;
+ const char *name;
+ u16 len, version;
+ u8 major, minor;
+
+ seq_puts(seq, "Command DB DUMP\n");
+
+ for (i = 0; i < MAX_SLV_ID; i++) {
+ rsc = &cmd_db_header->header[i];
+ if (!rsc->slv_id)
+ break;
+
+ switch (le16_to_cpu(rsc->slv_id)) {
+ case CMD_DB_HW_ARC:
+ name = "ARC";
+ break;
+ case CMD_DB_HW_VRM:
+ name = "VRM";
+ break;
+ case CMD_DB_HW_BCM:
+ name = "BCM";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ }
+
+ version = le16_to_cpu(rsc->version);
+ major = version >> 8;
+ minor = version;
+
+ seq_printf(seq, "Slave %s (v%u.%u)\n", name, major, minor);
+ seq_puts(seq, "-------------------------\n");
+
+ ent = rsc_to_entry_header(rsc);
+ for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) {
+ seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr),
+ (int)strnlen(ent->id, sizeof(ent->id)), ent->id);
+
+ len = le16_to_cpu(ent->len);
+ if (len) {
+ seq_printf(seq, " [%*ph]",
+ len, rsc_offset(rsc, ent));
+ }
+ seq_putc(seq, '\n');
+ }
+ }
+
+ return 0;
+}
+
+static int open_cmd_db_debugfs(struct inode *inode, struct file *file)
+{
+ return single_open(file, cmd_db_debugfs_dump, inode->i_private);
+}
+#endif
+
+static const struct file_operations cmd_db_debugfs_ops = {
+#ifdef CONFIG_DEBUG_FS
+ .open = open_cmd_db_debugfs,
+#endif
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int cmd_db_dev_probe(struct platform_device *pdev)
+{
+ struct reserved_mem *rmem;
+ int ret = 0;
+
+ rmem = of_reserved_mem_lookup(pdev->dev.of_node);
+ if (!rmem) {
+ dev_err(&pdev->dev, "failed to acquire memory region\n");
+ return -EINVAL;
+ }
+
+ cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
+ if (!cmd_db_header) {
+ ret = -ENOMEM;
+ cmd_db_header = NULL;
+ return ret;
+ }
+
+ if (!cmd_db_magic_matches(cmd_db_header)) {
+ dev_err(&pdev->dev, "Invalid Command DB Magic\n");
+ return -EINVAL;
+ }
+
+ debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
+
+ device_set_pm_not_required(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id cmd_db_match_table[] = {
+ { .compatible = "qcom,cmd-db" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cmd_db_match_table);
+
+static struct platform_driver cmd_db_dev_driver = {
+ .probe = cmd_db_dev_probe,
+ .driver = {
+ .name = "cmd-db",
+ .of_match_table = cmd_db_match_table,
+ .suppress_bind_attrs = true,
+ },
+};
+
+static int __init cmd_db_device_init(void)
+{
+ return platform_driver_register(&cmd_db_dev_driver);
+}
+core_initcall(cmd_db_device_init);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
new file mode 100644
index 000000000000..e3cf1beff803
--- /dev/null
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+
+#ifndef __RPM_INTERNAL_H__
+#define __RPM_INTERNAL_H__
+
+#include <linux/bitmap.h>
+#include <linux/wait.h>
+#include <soc/qcom/tcs.h>
+
+#define TCS_TYPE_NR 4
+#define MAX_CMDS_PER_TCS 16
+#define MAX_TCS_PER_TYPE 3
+#define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
+#define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
+
+struct rsc_drv;
+
+/**
+ * struct tcs_group: group of Trigger Command Sets (TCS) to send state requests
+ * to the controller
+ *
+ * @drv: The controller.
+ * @type: Type of the TCS in this group - active, sleep, wake.
+ * @mask: Mask of the TCSes relative to all the TCSes in the RSC.
+ * @offset: Start of the TCS group relative to the TCSes in the RSC.
+ * @num_tcs: Number of TCSes in this type.
+ * @ncpt: Number of commands in each TCS.
+ * @req: Requests that are sent from the TCS; only used for ACTIVE_ONLY
+ * transfers (could be on a wake/sleep TCS if we are borrowing for
+ * an ACTIVE_ONLY transfer).
+ * Start: grab drv->lock, set req, set tcs_in_use, drop drv->lock,
+ * trigger
+ * End: get irq, access req,
+ * grab drv->lock, clear tcs_in_use, drop drv->lock
+ * @slots: Indicates which of @cmd_addr are occupied; only used for
+ * SLEEP / WAKE TCSs. Things are tightly packed in the
+ * case that (ncpt < MAX_CMDS_PER_TCS). That is if ncpt = 2 and
+ * MAX_CMDS_PER_TCS = 16 then bit[2] = the first bit in 2nd TCS.
+ */
+struct tcs_group {
+ struct rsc_drv *drv;
+ int type;
+ u32 mask;
+ u32 offset;
+ int num_tcs;
+ int ncpt;
+ const struct tcs_request *req[MAX_TCS_PER_TYPE];
+ DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
+};
+
+/**
+ * struct rpmh_request: the message to be sent to rpmh-rsc
+ *
+ * @msg: the request
+ * @cmd: the payload that will be part of the @msg
+ * @completion: triggered when request is done
+ * @dev: the device making the request
+ * @needs_free: check to free dynamically allocated request object
+ */
+struct rpmh_request {
+ struct tcs_request msg;
+ struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
+ struct completion *completion;
+ const struct device *dev;
+ bool needs_free;
+};
+
+/**
+ * struct rpmh_ctrlr: our representation of the controller
+ *
+ * @cache: the list of cached requests
+ * @cache_lock: synchronize access to the cache data
+ * @dirty: was the cache updated since flush
+ * @batch_cache: Cache sleep and wake requests sent as batch
+ */
+struct rpmh_ctrlr {
+ struct list_head cache;
+ spinlock_t cache_lock;
+ bool dirty;
+ struct list_head batch_cache;
+};
+
+struct rsc_ver {
+ u32 major;
+ u32 minor;
+};
+
+/**
+ * struct rsc_drv: the Direct Resource Voter (DRV) of the
+ * Resource State Coordinator controller (RSC)
+ *
+ * @name: Controller identifier.
+ * @base: Start address of the DRV registers in this controller.
+ * @tcs_base: Start address of the TCS registers in this controller.
+ * @id: Instance id in the controller (Direct Resource Voter).
+ * @num_tcs: Number of TCSes in this DRV.
+ * @rsc_pm: CPU PM notifier for controller.
+ * Used when solver mode is not present.
+ * @cpus_in_pm: Number of CPUs not in idle power collapse.
+ * Used when solver mode and "power-domains" is not present.
+ * @genpd_nb: PM Domain notifier for cluster genpd notifications.
+ * @tcs: TCS groups.
+ * @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY
+ * transfers, but might show a sleep/wake TCS in use if
+ * it was borrowed for an active_only transfer. You
+ * must hold the lock in this struct (AKA drv->lock) in
+ * order to update this.
+ * @lock: Synchronize state of the controller. If RPMH's cache
+ * lock will also be held, the order is: drv->lock then
+ * cache_lock.
+ * @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a
+ * slot
+ * @client: Handle to the DRV's client.
+ * @dev: RSC device.
+ */
+struct rsc_drv {
+ const char *name;
+ void __iomem *base;
+ void __iomem *tcs_base;
+ int id;
+ int num_tcs;
+ struct notifier_block rsc_pm;
+ struct notifier_block genpd_nb;
+ atomic_t cpus_in_pm;
+ struct tcs_group tcs[TCS_TYPE_NR];
+ DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
+ spinlock_t lock;
+ wait_queue_head_t tcs_wait;
+ struct rpmh_ctrlr client;
+ struct device *dev;
+ struct rsc_ver ver;
+ u32 *regs;
+};
+
+int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
+int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
+ const struct tcs_request *msg);
+void rpmh_rsc_invalidate(struct rsc_drv *drv);
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv);
+
+void rpmh_tx_done(const struct tcs_request *msg);
+int rpmh_flush(struct rpmh_ctrlr *ctrlr);
+
+#endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
new file mode 100644
index 000000000000..de86009ecd91
--- /dev/null
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -0,0 +1,1162 @@
+// 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(const struct rsc_drv *drv, int reg, int tcs_id)
+{
+ return drv->tcs_base + drv->regs[RSC_DRV_TCS_OFFSET] * tcs_id + reg;
+}
+
+static inline void __iomem *
+tcs_cmd_addr(const struct rsc_drv *drv, int reg, int tcs_id, int cmd_id)
+{
+ return tcs_reg_addr(drv, reg, tcs_id) + drv->regs[RSC_DRV_CMD_OFFSET] * cmd_id;
+}
+
+static u32 read_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
+ int cmd_id)
+{
+ return readl_relaxed(tcs_cmd_addr(drv, reg, tcs_id, cmd_id));
+}
+
+static u32 read_tcs_reg(const struct rsc_drv *drv, int reg, int tcs_id)
+{
+ return readl_relaxed(tcs_reg_addr(drv, reg, tcs_id));
+}
+
+static void write_tcs_cmd(const struct rsc_drv *drv, int reg, int tcs_id,
+ int cmd_id, u32 data)
+{
+ writel_relaxed(data, tcs_cmd_addr(drv, reg, tcs_id, cmd_id));
+}
+
+static void write_tcs_reg(const struct rsc_drv *drv, int reg, int tcs_id,
+ u32 data)
+{
+ writel_relaxed(data, tcs_reg_addr(drv, reg, tcs_id));
+}
+
+static void write_tcs_reg_sync(const struct rsc_drv *drv, int reg, int tcs_id,
+ u32 data)
+{
+ int i;
+
+ writel(data, tcs_reg_addr(drv, reg, tcs_id));
+
+ /*
+ * Wait until we read back the same value. Use a counter rather than
+ * ktime for timeout since this may be called after timekeeping stops.
+ */
+ for (i = 0; i < USEC_PER_SEC; i++) {
+ if (readl(tcs_reg_addr(drv, reg, tcs_id)) == data)
+ return;
+ udelay(1);
+ }
+ pr_err("%s: error writing %#x to %d:%#x\n", drv->name,
+ data, tcs_id, reg);
+}
+
+/**
+ * tcs_invalidate() - Invalidate all TCSes of the given type (sleep or wake).
+ * @drv: The RSC controller.
+ * @type: SLEEP_TCS or WAKE_TCS
+ *
+ * This will clear the "slots" variable of the given tcs_group and also
+ * tell the hardware to forget about all entries.
+ *
+ * The caller must ensure that no other RPMH actions are happening when this
+ * function is called, since otherwise the device may immediately become
+ * used again even before this function exits.
+ */
+static void tcs_invalidate(struct rsc_drv *drv, int type)
+{
+ int m;
+ struct tcs_group *tcs = &drv->tcs[type];
+
+ /* Caller ensures nobody else is running so no lock */
+ if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
+ return;
+
+ for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
+ write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], m, 0);
+
+ bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
+}
+
+/**
+ * rpmh_rsc_invalidate() - Invalidate sleep and wake TCSes.
+ * @drv: The RSC controller.
+ *
+ * The caller must ensure that no other RPMH actions are happening when this
+ * function is called, since otherwise the device may immediately become
+ * used again even before this function exits.
+ */
+void rpmh_rsc_invalidate(struct rsc_drv *drv)
+{
+ tcs_invalidate(drv, SLEEP_TCS);
+ tcs_invalidate(drv, WAKE_TCS);
+}
+
+/**
+ * get_tcs_for_msg() - Get the tcs_group used to send the given message.
+ * @drv: The RSC controller.
+ * @msg: The message we want to send.
+ *
+ * This is normally pretty straightforward except if we are trying to send
+ * an ACTIVE_ONLY message but don't have any active_only TCSes.
+ *
+ * Return: A pointer to a tcs_group or an ERR_PTR.
+ */
+static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
+ const struct tcs_request *msg)
+{
+ int type;
+ struct tcs_group *tcs;
+
+ switch (msg->state) {
+ case RPMH_ACTIVE_ONLY_STATE:
+ type = ACTIVE_TCS;
+ break;
+ case RPMH_WAKE_ONLY_STATE:
+ type = WAKE_TCS;
+ break;
+ case RPMH_SLEEP_STATE:
+ type = SLEEP_TCS;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ /*
+ * If we are making an active request on a RSC that does not have a
+ * dedicated TCS for active state use, then re-purpose a wake TCS to
+ * send active votes. This is safe because we ensure any active-only
+ * transfers have finished before we use it (maybe by running from
+ * the last CPU in PM code).
+ */
+ tcs = &drv->tcs[type];
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE && !tcs->num_tcs)
+ tcs = &drv->tcs[WAKE_TCS];
+
+ return tcs;
+}
+
+/**
+ * get_req_from_tcs() - Get a stashed request that was xfering on the given TCS.
+ * @drv: The RSC controller.
+ * @tcs_id: The global ID of this TCS.
+ *
+ * For ACTIVE_ONLY transfers we want to call back into the client when the
+ * transfer finishes. To do this we need the "request" that the client
+ * originally provided us. This function grabs the request that we stashed
+ * when we started the transfer.
+ *
+ * This only makes sense for ACTIVE_ONLY transfers since those are the only
+ * ones we track sending (the only ones we enable interrupts for and the only
+ * ones we call back to the client for).
+ *
+ * Return: The stashed request.
+ */
+static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
+ int tcs_id)
+{
+ struct tcs_group *tcs;
+ int i;
+
+ for (i = 0; i < TCS_TYPE_NR; i++) {
+ tcs = &drv->tcs[i];
+ if (tcs->mask & BIT(tcs_id))
+ return tcs->req[tcs_id - tcs->offset];
+ }
+
+ return NULL;
+}
+
+/**
+ * __tcs_set_trigger() - Start xfer on a TCS or unset trigger on a borrowed TCS
+ * @drv: The controller.
+ * @tcs_id: The global ID of this TCS.
+ * @trigger: If true then untrigger/retrigger. If false then just untrigger.
+ *
+ * In the normal case we only ever call with "trigger=true" to start a
+ * transfer. That will un-trigger/disable the TCS from the last transfer
+ * then trigger/enable for this transfer.
+ *
+ * If we borrowed a wake TCS for an active-only transfer we'll also call
+ * this function with "trigger=false" to just do the un-trigger/disable
+ * before using the TCS for wake purposes again.
+ *
+ * Note that the AP is only in charge of triggering active-only transfers.
+ * The AP never triggers sleep/wake values using this function.
+ */
+static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
+{
+ u32 enable;
+ u32 reg = drv->regs[RSC_DRV_CONTROL];
+
+ /*
+ * HW req: Clear the DRV_CONTROL and enable TCS again
+ * While clearing ensure that the AMC mode trigger is cleared
+ * and then the mode enable is cleared.
+ */
+ enable = read_tcs_reg(drv, reg, tcs_id);
+ enable &= ~TCS_AMC_MODE_TRIGGER;
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
+ enable &= ~TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
+
+ if (trigger) {
+ /* Enable the AMC mode on the TCS and then trigger the TCS */
+ enable = TCS_AMC_MODE_ENABLE;
+ write_tcs_reg_sync(drv, reg, tcs_id, enable);
+ enable |= TCS_AMC_MODE_TRIGGER;
+ write_tcs_reg(drv, reg, tcs_id, enable);
+ }
+}
+
+/**
+ * enable_tcs_irq() - Enable or disable interrupts on the given TCS.
+ * @drv: The controller.
+ * @tcs_id: The global ID of this TCS.
+ * @enable: If true then enable; if false then disable
+ *
+ * We only ever call this when we borrow a wake TCS for an active-only
+ * transfer. For active-only TCSes interrupts are always left enabled.
+ */
+static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
+{
+ u32 data;
+ u32 reg = drv->regs[RSC_DRV_IRQ_ENABLE];
+
+ data = readl_relaxed(drv->tcs_base + reg);
+ if (enable)
+ data |= BIT(tcs_id);
+ else
+ data &= ~BIT(tcs_id);
+ writel_relaxed(data, drv->tcs_base + reg);
+}
+
+/**
+ * tcs_tx_done() - TX Done interrupt handler.
+ * @irq: The IRQ number (ignored).
+ * @p: Pointer to "struct rsc_drv".
+ *
+ * Called for ACTIVE_ONLY transfers (those are the only ones we enable the
+ * IRQ for) when a transfer is done.
+ *
+ * Return: IRQ_HANDLED
+ */
+static irqreturn_t tcs_tx_done(int irq, void *p)
+{
+ struct rsc_drv *drv = p;
+ int i;
+ unsigned long irq_status;
+ const struct tcs_request *req;
+
+ irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
+
+ for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
+ req = get_req_from_tcs(drv, i);
+ if (WARN_ON(!req))
+ goto skip;
+
+ trace_rpmh_tx_done(drv, i, req);
+
+ /*
+ * If wake tcs was re-purposed for sending active
+ * votes, clear AMC trigger & enable modes and
+ * disable interrupt for this TCS
+ */
+ if (!drv->tcs[ACTIVE_TCS].num_tcs)
+ __tcs_set_trigger(drv, i, false);
+skip:
+ /* Reclaim the TCS */
+ write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
+ writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
+ spin_lock(&drv->lock);
+ clear_bit(i, drv->tcs_in_use);
+ /*
+ * Disable interrupt for WAKE TCS to avoid being
+ * spammed with interrupts coming when the solver
+ * sends its wake votes.
+ */
+ if (!drv->tcs[ACTIVE_TCS].num_tcs)
+ enable_tcs_irq(drv, i, false);
+ spin_unlock(&drv->lock);
+ wake_up(&drv->tcs_wait);
+ if (req)
+ rpmh_tx_done(req);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * __tcs_buffer_write() - Write to TCS hardware from a request; don't trigger.
+ * @drv: The controller.
+ * @tcs_id: The global ID of this TCS.
+ * @cmd_id: The index within the TCS to start writing.
+ * @msg: The message we want to send, which will contain several addr/data
+ * pairs to program (but few enough that they all fit in one TCS).
+ *
+ * This is used for all types of transfers (active, sleep, and wake).
+ */
+static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
+ const struct tcs_request *msg)
+{
+ u32 msgid;
+ u32 cmd_msgid = CMD_MSGID_LEN | CMD_MSGID_WRITE;
+ u32 cmd_enable = 0;
+ struct tcs_cmd *cmd;
+ int i, j;
+
+ /* Convert all commands to RR when the request has wait_for_compl set */
+ cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0;
+
+ for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) {
+ cmd = &msg->cmds[i];
+ cmd_enable |= BIT(j);
+ msgid = cmd_msgid;
+ /*
+ * Additionally, if the cmd->wait is set, make the command
+ * response reqd even if the overall request was fire-n-forget.
+ */
+ msgid |= cmd->wait ? CMD_MSGID_RESP_REQ : 0;
+
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
+ write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
+ trace_rpmh_send_msg(drv, tcs_id, msg->state, j, msgid, cmd);
+ }
+
+ cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
+ write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
+}
+
+/**
+ * check_for_req_inflight() - Look to see if conflicting cmds are in flight.
+ * @drv: The controller.
+ * @tcs: A pointer to the tcs_group used for ACTIVE_ONLY transfers.
+ * @msg: The message we want to send, which will contain several addr/data
+ * pairs to program (but few enough that they all fit in one TCS).
+ *
+ * This will walk through the TCSes in the group and check if any of them
+ * appear to be sending to addresses referenced in the message. If it finds
+ * one it'll return -EBUSY.
+ *
+ * Only for use for active-only transfers.
+ *
+ * Must be called with the drv->lock held since that protects tcs_in_use.
+ *
+ * Return: 0 if nothing in flight or -EBUSY if we should try again later.
+ * The caller must re-enable interrupts between tries since that's
+ * the only way tcs_in_use will ever be updated and the only way
+ * RSC_DRV_CMD_ENABLE will ever be cleared.
+ */
+static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
+ const struct tcs_request *msg)
+{
+ unsigned long curr_enabled;
+ u32 addr;
+ int j, k;
+ int i = tcs->offset;
+
+ for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
+ curr_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i);
+
+ for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
+ addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
+ for (k = 0; k < msg->num_cmds; k++) {
+ if (cmd_db_match_resource_addr(msg->cmds[k].addr, addr))
+ return -EBUSY;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * find_free_tcs() - Find free tcs in the given tcs_group; only for active.
+ * @tcs: A pointer to the active-only tcs_group (or the wake tcs_group if
+ * we borrowed it because there are zero active-only ones).
+ *
+ * Must be called with the drv->lock held since that protects tcs_in_use.
+ *
+ * Return: The first tcs that's free or -EBUSY if all in use.
+ */
+static int find_free_tcs(struct tcs_group *tcs)
+{
+ const struct rsc_drv *drv = tcs->drv;
+ unsigned long i;
+ unsigned long max = tcs->offset + tcs->num_tcs;
+
+ i = find_next_zero_bit(drv->tcs_in_use, max, tcs->offset);
+ if (i >= max)
+ return -EBUSY;
+
+ return i;
+}
+
+/**
+ * claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active.
+ * @drv: The controller.
+ * @tcs: The tcs_group used for ACTIVE_ONLY transfers.
+ * @msg: The data to be sent.
+ *
+ * Claims a tcs in the given tcs_group while making sure that no existing cmd
+ * is in flight that would conflict with the one in @msg.
+ *
+ * Context: Must be called with the drv->lock held since that protects
+ * tcs_in_use.
+ *
+ * Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight
+ * or the tcs_group is full.
+ */
+static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
+ const struct tcs_request *msg)
+{
+ int ret;
+
+ /*
+ * The h/w does not like if we send a request to the same address,
+ * when one is already in-flight or being processed.
+ */
+ ret = check_for_req_inflight(drv, tcs, msg);
+ if (ret)
+ return ret;
+
+ return find_free_tcs(tcs);
+}
+
+/**
+ * rpmh_rsc_send_data() - Write / trigger active-only message.
+ * @drv: The controller.
+ * @msg: The data to be sent.
+ *
+ * NOTES:
+ * - This is only used for "ACTIVE_ONLY" since the limitations of this
+ * function don't make sense for sleep/wake cases.
+ * - To do the transfer, we will grab a whole TCS for ourselves--we don't
+ * try to share. If there are none available we'll wait indefinitely
+ * for a free one.
+ * - This function will not wait for the commands to be finished, only for
+ * data to be programmed into the RPMh. See rpmh_tx_done() which will
+ * be called when the transfer is fully complete.
+ * - This function must be called with interrupts enabled. If the hardware
+ * is busy doing someone else's transfer we need that transfer to fully
+ * finish so that we can have the hardware, and to fully finish it needs
+ * the interrupt handler to run. If the interrupts is set to run on the
+ * active CPU this can never happen if interrupts are disabled.
+ *
+ * Return: 0 on success, -EINVAL on error.
+ */
+int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ struct tcs_group *tcs;
+ int tcs_id;
+
+ might_sleep();
+
+ tcs = get_tcs_for_msg(drv, msg);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ spin_lock_irq(&drv->lock);
+
+ /* Wait forever for a free tcs. It better be there eventually! */
+ wait_event_lock_irq(drv->tcs_wait,
+ (tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
+ drv->lock);
+
+ tcs->req[tcs_id - tcs->offset] = msg;
+ set_bit(tcs_id, drv->tcs_in_use);
+ if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
+ /*
+ * Clear previously programmed WAKE commands in selected
+ * repurposed TCS to avoid triggering them. tcs->slots will be
+ * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
+ */
+ write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
+ enable_tcs_irq(drv, tcs_id, true);
+ }
+ spin_unlock_irq(&drv->lock);
+
+ /*
+ * These two can be done after the lock is released because:
+ * - We marked "tcs_in_use" under lock.
+ * - Once "tcs_in_use" has been marked nobody else could be writing
+ * to these registers until the interrupt goes off.
+ * - The interrupt can't go off until we trigger w/ the last line
+ * of __tcs_set_trigger() below.
+ */
+ __tcs_buffer_write(drv, tcs_id, 0, msg);
+ __tcs_set_trigger(drv, tcs_id, true);
+
+ return 0;
+}
+
+/**
+ * find_slots() - Find a place to write the given message.
+ * @tcs: The tcs group to search.
+ * @msg: The message we want to find room for.
+ * @tcs_id: If we return 0 from the function, we return the global ID of the
+ * TCS to write to here.
+ * @cmd_id: If we return 0 from the function, we return the index of
+ * the command array of the returned TCS where the client should
+ * start writing the message.
+ *
+ * Only for use on sleep/wake TCSes since those are the only ones we maintain
+ * tcs->slots for.
+ *
+ * Return: -ENOMEM if there was no room, else 0.
+ */
+static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
+ int *tcs_id, int *cmd_id)
+{
+ int slot, offset;
+ int i = 0;
+
+ /* Do over, until we can fit the full payload in a single TCS */
+ do {
+ slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
+ i, msg->num_cmds, 0);
+ if (slot >= tcs->num_tcs * tcs->ncpt)
+ return -ENOMEM;
+ i += tcs->ncpt;
+ } while (slot + msg->num_cmds - 1 >= i);
+
+ bitmap_set(tcs->slots, slot, msg->num_cmds);
+
+ offset = slot / tcs->ncpt;
+ *tcs_id = offset + tcs->offset;
+ *cmd_id = slot % tcs->ncpt;
+
+ return 0;
+}
+
+/**
+ * rpmh_rsc_write_ctrl_data() - Write request to controller but don't trigger.
+ * @drv: The controller.
+ * @msg: The data to be written to the controller.
+ *
+ * This should only be called for sleep/wake state, never active-only
+ * state.
+ *
+ * The caller must ensure that no other RPMH actions are happening and the
+ * controller is idle when this function is called since it runs lockless.
+ *
+ * Return: 0 if no error; else -error.
+ */
+int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg)
+{
+ struct tcs_group *tcs;
+ int tcs_id = 0, cmd_id = 0;
+ int ret;
+
+ tcs = get_tcs_for_msg(drv, msg);
+ if (IS_ERR(tcs))
+ return PTR_ERR(tcs);
+
+ /* find the TCS id and the command in the TCS to write to */
+ ret = find_slots(tcs, msg, &tcs_id, &cmd_id);
+ if (!ret)
+ __tcs_buffer_write(drv, tcs_id, cmd_id, msg);
+
+ return ret;
+}
+
+/**
+ * rpmh_rsc_ctrlr_is_busy() - Check if any of the AMCs are busy.
+ * @drv: The controller
+ *
+ * Checks if any of the AMCs are busy in handling ACTIVE sets.
+ * This is called from the last cpu powering down before flushing
+ * SLEEP and WAKE sets. If AMCs are busy, controller can not enter
+ * power collapse, so deny from the last cpu's pm notification.
+ *
+ * Context: Must be called with the drv->lock held.
+ *
+ * Return:
+ * * False - AMCs are idle
+ * * True - AMCs are busy
+ */
+static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
+{
+ unsigned long set;
+ const struct tcs_group *tcs = &drv->tcs[ACTIVE_TCS];
+ unsigned long max;
+
+ /*
+ * If we made an active request on a RSC that does not have a
+ * dedicated TCS for active state use, then re-purposed wake TCSes
+ * should be checked for not busy, because we used wake TCSes for
+ * active requests in this case.
+ */
+ if (!tcs->num_tcs)
+ tcs = &drv->tcs[WAKE_TCS];
+
+ max = tcs->offset + tcs->num_tcs;
+ set = find_next_bit(drv->tcs_in_use, max, tcs->offset);
+
+ return set < max;
+}
+
+/**
+ * rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS.
+ * @drv: The controller
+ *
+ * Writes maximum wakeup cycles when called from suspend.
+ * Writes earliest hrtimer wakeup when called from idle.
+ */
+void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
+{
+ ktime_t now, wakeup;
+ u64 wakeup_us, wakeup_cycles = ~0;
+ u32 lo, hi;
+
+ if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call)
+ return;
+
+ /* Set highest time when system (timekeeping) is suspended */
+ if (system_state == SYSTEM_SUSPEND)
+ goto exit;
+
+ /* Find the earliest hrtimer wakeup from online cpus */
+ wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev);
+
+ /* Find the relative wakeup in kernel time scale */
+ now = ktime_get();
+ wakeup = ktime_sub(wakeup, now);
+ wakeup_us = ktime_to_us(wakeup);
+
+ /* Convert the wakeup to arch timer scale */
+ wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
+ wakeup_cycles += arch_timer_read_counter();
+
+exit:
+ lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK;
+ hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE;
+ hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK;
+ hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID;
+
+ writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO);
+ writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI);
+}
+
+/**
+ * rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy.
+ * @nfb: Pointer to the notifier block in struct rsc_drv.
+ * @action: CPU_PM_ENTER, CPU_PM_ENTER_FAILED, or CPU_PM_EXIT.
+ * @v: Unused
+ *
+ * This function is given to cpu_pm_register_notifier so we can be informed
+ * about when CPUs go down. When all CPUs go down we know no more active
+ * transfers will be started so we write sleep/wake sets. This function gets
+ * called from cpuidle code paths and also at system suspend time.
+ *
+ * If its last CPU going down and AMCs are not busy then writes cached sleep
+ * and wake messages to TCSes. The firmware then takes care of triggering
+ * them when entering deepest low power modes.
+ *
+ * Return: See cpu_pm_register_notifier()
+ */
+static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb,
+ unsigned long action, void *v)
+{
+ struct rsc_drv *drv = container_of(nfb, struct rsc_drv, rsc_pm);
+ int ret = NOTIFY_OK;
+ int cpus_in_pm;
+
+ switch (action) {
+ case CPU_PM_ENTER:
+ cpus_in_pm = atomic_inc_return(&drv->cpus_in_pm);
+ /*
+ * NOTE: comments for num_online_cpus() point out that it's
+ * only a snapshot so we need to be careful. It should be OK
+ * for us to use, though. It's important for us not to miss
+ * if we're the last CPU going down so it would only be a
+ * problem if a CPU went offline right after we did the check
+ * AND that CPU was not idle AND that CPU was the last non-idle
+ * CPU. That can't happen. CPUs would have to come out of idle
+ * before the CPU could go offline.
+ */
+ if (cpus_in_pm < num_online_cpus())
+ return NOTIFY_OK;
+ break;
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ atomic_dec(&drv->cpus_in_pm);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ /*
+ * It's likely we're on the last CPU. Grab the drv->lock and write
+ * out the sleep/wake commands to RPMH hardware. Grabbing the lock
+ * means that if we race with another CPU coming up we are still
+ * guaranteed to be safe. If another CPU came up just after we checked
+ * and has grabbed the lock or started an active transfer then we'll
+ * notice we're busy and abort. If another CPU comes up after we start
+ * flushing it will be blocked from starting an active transfer until
+ * we're done flushing. If another CPU starts an active transfer after
+ * we release the lock we're still OK because we're no longer the last
+ * CPU.
+ */
+ if (spin_trylock(&drv->lock)) {
+ if (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client))
+ ret = NOTIFY_BAD;
+ spin_unlock(&drv->lock);
+ } else {
+ /* Another CPU must be up */
+ return NOTIFY_OK;
+ }
+
+ if (ret == NOTIFY_BAD) {
+ /* Double-check if we're here because someone else is up */
+ if (cpus_in_pm < num_online_cpus())
+ ret = NOTIFY_OK;
+ else
+ /* We won't be called w/ CPU_PM_ENTER_FAILED */
+ atomic_dec(&drv->cpus_in_pm);
+ }
+
+ return ret;
+}
+
+/**
+ * rpmh_rsc_pd_callback() - Check if any of the AMCs are busy.
+ * @nfb: Pointer to the genpd notifier block in struct rsc_drv.
+ * @action: GENPD_NOTIFY_PRE_OFF, GENPD_NOTIFY_OFF, GENPD_NOTIFY_PRE_ON or GENPD_NOTIFY_ON.
+ * @v: Unused
+ *
+ * This function is given to dev_pm_genpd_add_notifier() so we can be informed
+ * about when cluster-pd is going down. When cluster go down we know no more active
+ * transfers will be started so we write sleep/wake sets. This function gets
+ * called from cpuidle code paths and also at system suspend time.
+ *
+ * If AMCs are not busy then writes cached sleep and wake messages to TCSes.
+ * The firmware then takes care of triggering them when entering deepest low power modes.
+ *
+ * Return:
+ * * NOTIFY_OK - success
+ * * NOTIFY_BAD - failure
+ */
+static int rpmh_rsc_pd_callback(struct notifier_block *nfb,
+ unsigned long action, void *v)
+{
+ struct rsc_drv *drv = container_of(nfb, struct rsc_drv, genpd_nb);
+
+ /* We don't need to lock as genpd on/off are serialized */
+ if ((action == GENPD_NOTIFY_PRE_OFF) &&
+ (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)))
+ return NOTIFY_BAD;
+
+ return NOTIFY_OK;
+}
+
+static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev)
+{
+ int ret;
+
+ pm_runtime_enable(dev);
+ drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback;
+ ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb);
+ if (ret)
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
+{
+ struct tcs_type_config {
+ u32 type;
+ u32 n;
+ } tcs_cfg[TCS_TYPE_NR] = { { 0 } };
+ struct device_node *dn = pdev->dev.of_node;
+ u32 config, max_tcs, ncpt, offset;
+ int i, ret, n, st = 0;
+ struct tcs_group *tcs;
+
+ ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
+ if (ret)
+ return ret;
+ drv->tcs_base = drv->base + offset;
+
+ config = readl_relaxed(drv->base + drv->regs[DRV_PRNT_CHLD_CONFIG]);
+
+ max_tcs = config;
+ max_tcs &= DRV_NUM_TCS_MASK << (DRV_NUM_TCS_SHIFT * drv->id);
+ max_tcs = max_tcs >> (DRV_NUM_TCS_SHIFT * drv->id);
+
+ ncpt = config & (DRV_NCPT_MASK << DRV_NCPT_SHIFT);
+ ncpt = ncpt >> DRV_NCPT_SHIFT;
+
+ n = of_property_count_u32_elems(dn, "qcom,tcs-config");
+ if (n != 2 * TCS_TYPE_NR)
+ return -EINVAL;
+
+ for (i = 0; i < TCS_TYPE_NR; i++) {
+ ret = of_property_read_u32_index(dn, "qcom,tcs-config",
+ i * 2, &tcs_cfg[i].type);
+ if (ret)
+ return ret;
+ if (tcs_cfg[i].type >= TCS_TYPE_NR)
+ return -EINVAL;
+
+ ret = of_property_read_u32_index(dn, "qcom,tcs-config",
+ i * 2 + 1, &tcs_cfg[i].n);
+ if (ret)
+ return ret;
+ if (tcs_cfg[i].n > MAX_TCS_PER_TYPE)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < TCS_TYPE_NR; i++) {
+ tcs = &drv->tcs[tcs_cfg[i].type];
+ if (tcs->drv)
+ return -EINVAL;
+ tcs->drv = drv;
+ tcs->type = tcs_cfg[i].type;
+ tcs->num_tcs = tcs_cfg[i].n;
+ tcs->ncpt = ncpt;
+
+ if (!tcs->num_tcs || tcs->type == CONTROL_TCS)
+ continue;
+
+ if (st + tcs->num_tcs > max_tcs ||
+ st + tcs->num_tcs >= BITS_PER_BYTE * sizeof(tcs->mask))
+ return -EINVAL;
+
+ tcs->mask = ((1 << tcs->num_tcs) - 1) << st;
+ tcs->offset = st;
+ st += tcs->num_tcs;
+ }
+
+ drv->num_tcs = st;
+
+ return 0;
+}
+
+static int rpmh_rsc_probe(struct platform_device *pdev)
+{
+ struct device_node *dn = pdev->dev.of_node;
+ struct rsc_drv *drv;
+ char drv_id[10] = {0};
+ int ret, irq;
+ u32 solver_config;
+ u32 rsc_id;
+
+ /*
+ * Even though RPMh doesn't directly use cmd-db, all of its children
+ * do. To avoid adding this check to our children we'll do it now.
+ */
+ ret = cmd_db_ready();
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Command DB not available (%d)\n",
+ ret);
+ return ret;
+ }
+
+ drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
+ if (!drv)
+ return -ENOMEM;
+
+ ret = of_property_read_u32(dn, "qcom,drv-id", &drv->id);
+ if (ret)
+ return ret;
+
+ drv->name = of_get_property(dn, "label", NULL);
+ if (!drv->name)
+ drv->name = dev_name(&pdev->dev);
+
+ snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
+ drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id);
+ if (IS_ERR(drv->base))
+ return PTR_ERR(drv->base);
+
+ rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
+ drv->ver.major = rsc_id & (MAJOR_VER_MASK << MAJOR_VER_SHIFT);
+ drv->ver.major >>= MAJOR_VER_SHIFT;
+ drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
+ drv->ver.minor >>= MINOR_VER_SHIFT;
+
+ if (drv->ver.major == 3)
+ drv->regs = rpmh_rsc_reg_offset_ver_3_0;
+ else
+ drv->regs = rpmh_rsc_reg_offset_ver_2_7;
+
+ ret = rpmh_probe_tcs_config(pdev, drv);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&drv->lock);
+ init_waitqueue_head(&drv->tcs_wait);
+ bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
+
+ irq = platform_get_irq(pdev, drv->id);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done,
+ IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
+ drv->name, drv);
+ if (ret)
+ return ret;
+
+ /*
+ * CPU PM/genpd notification are not required for controllers that support
+ * 'HW solver' mode where they can be in autonomous mode executing low
+ * power mode to power down.
+ */
+ solver_config = readl_relaxed(drv->base + drv->regs[DRV_SOLVER_CONFIG]);
+ solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
+ solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
+ if (!solver_config) {
+ if (pdev->dev.pm_domain) {
+ ret = rpmh_rsc_pd_attach(drv, &pdev->dev);
+ if (ret)
+ return ret;
+ } else {
+ drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
+ cpu_pm_register_notifier(&drv->rsc_pm);
+ }
+ }
+
+ /* Enable the active TCS to send requests immediately */
+ writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
+ drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
+
+ spin_lock_init(&drv->client.cache_lock);
+ INIT_LIST_HEAD(&drv->client.cache);
+ INIT_LIST_HEAD(&drv->client.batch_cache);
+
+ dev_set_drvdata(&pdev->dev, drv);
+ drv->dev = &pdev->dev;
+
+ ret = devm_of_platform_populate(&pdev->dev);
+ if (ret && pdev->dev.pm_domain) {
+ dev_pm_genpd_remove_notifier(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id rpmh_drv_match[] = {
+ { .compatible = "qcom,rpmh-rsc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, rpmh_drv_match);
+
+static struct platform_driver rpmh_driver = {
+ .probe = rpmh_rsc_probe,
+ .driver = {
+ .name = "rpmh",
+ .of_match_table = rpmh_drv_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+static int __init rpmh_driver_init(void)
+{
+ return platform_driver_register(&rpmh_driver);
+}
+core_initcall(rpmh_driver_init);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
new file mode 100644
index 000000000000..8903ed956312
--- /dev/null
+++ b/drivers/soc/qcom/rpmh.c
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/atomic.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+#include <soc/qcom/rpmh.h>
+
+#include "rpmh-internal.h"
+
+#define RPMH_TIMEOUT_MS msecs_to_jiffies(10000)
+
+#define DEFINE_RPMH_MSG_ONSTACK(device, s, q, name) \
+ struct rpmh_request name = { \
+ .msg = { \
+ .state = s, \
+ .cmds = name.cmd, \
+ .num_cmds = 0, \
+ .wait_for_compl = true, \
+ }, \
+ .cmd = { { 0 } }, \
+ .completion = q, \
+ .dev = device, \
+ .needs_free = false, \
+ }
+
+#define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client)
+
+/**
+ * struct cache_req: the request object for caching
+ *
+ * @addr: the address of the resource
+ * @sleep_val: the sleep vote
+ * @wake_val: the wake vote
+ * @list: linked list obj
+ */
+struct cache_req {
+ u32 addr;
+ u32 sleep_val;
+ u32 wake_val;
+ struct list_head list;
+};
+
+/**
+ * struct batch_cache_req - An entry in our batch catch
+ *
+ * @list: linked list obj
+ * @count: number of messages
+ * @rpm_msgs: the messages
+ */
+
+struct batch_cache_req {
+ struct list_head list;
+ int count;
+ struct rpmh_request rpm_msgs[];
+};
+
+static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
+{
+ struct rsc_drv *drv = dev_get_drvdata(dev->parent);
+
+ return &drv->client;
+}
+
+void rpmh_tx_done(const struct tcs_request *msg)
+{
+ struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
+ msg);
+ struct completion *compl = rpm_msg->completion;
+ bool free = rpm_msg->needs_free;
+
+ if (!compl)
+ goto exit;
+
+ /* Signal the blocking thread we are done */
+ complete(compl);
+
+exit:
+ if (free)
+ kfree(rpm_msg);
+}
+
+static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr)
+{
+ struct cache_req *p, *req = NULL;
+
+ list_for_each_entry(p, &ctrlr->cache, list) {
+ if (p->addr == addr) {
+ req = p;
+ break;
+ }
+ }
+
+ return req;
+}
+
+static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
+ enum rpmh_state state,
+ struct tcs_cmd *cmd)
+{
+ struct cache_req *req;
+ unsigned long flags;
+ u32 old_sleep_val, old_wake_val;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ req = __find_req(ctrlr, cmd->addr);
+ if (req)
+ goto existing;
+
+ req = kzalloc(sizeof(*req), GFP_ATOMIC);
+ if (!req) {
+ req = ERR_PTR(-ENOMEM);
+ goto unlock;
+ }
+
+ req->addr = cmd->addr;
+ req->sleep_val = req->wake_val = UINT_MAX;
+ list_add_tail(&req->list, &ctrlr->cache);
+
+existing:
+ old_sleep_val = req->sleep_val;
+ old_wake_val = req->wake_val;
+
+ switch (state) {
+ case RPMH_ACTIVE_ONLY_STATE:
+ case RPMH_WAKE_ONLY_STATE:
+ req->wake_val = cmd->data;
+ break;
+ case RPMH_SLEEP_STATE:
+ req->sleep_val = cmd->data;
+ break;
+ }
+
+ ctrlr->dirty |= (req->sleep_val != old_sleep_val ||
+ req->wake_val != old_wake_val) &&
+ req->sleep_val != UINT_MAX &&
+ req->wake_val != UINT_MAX;
+
+unlock:
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+
+ return req;
+}
+
+/**
+ * __rpmh_write: Cache and send the RPMH request
+ *
+ * @dev: The device making the request
+ * @state: Active/Sleep request type
+ * @rpm_msg: The data that needs to be sent (cmds).
+ *
+ * Cache the RPMH request and send if the state is ACTIVE_ONLY.
+ * SLEEP/WAKE_ONLY requests are not sent to the controller at
+ * this time. Use rpmh_flush() to send them to the controller.
+ */
+static int __rpmh_write(const struct device *dev, enum rpmh_state state,
+ struct rpmh_request *rpm_msg)
+{
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ int ret = -EINVAL;
+ struct cache_req *req;
+ int i;
+
+ /* Cache the request in our store and link the payload */
+ for (i = 0; i < rpm_msg->msg.num_cmds; i++) {
+ req = cache_rpm_request(ctrlr, state, &rpm_msg->msg.cmds[i]);
+ if (IS_ERR(req))
+ return PTR_ERR(req);
+ }
+
+ if (state == RPMH_ACTIVE_ONLY_STATE) {
+ ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
+ } else {
+ /* Clean up our call by spoofing tx_done */
+ ret = 0;
+ rpmh_tx_done(&rpm_msg->msg);
+ }
+
+ return ret;
+}
+
+static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
+ return -EINVAL;
+
+ memcpy(req->cmd, cmd, n * sizeof(*cmd));
+
+ req->msg.state = state;
+ req->msg.cmds = req->cmd;
+ req->msg.num_cmds = n;
+
+ return 0;
+}
+
+/**
+ * rpmh_write_async: Write a set of RPMH commands
+ *
+ * @dev: The device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The number of elements in payload
+ *
+ * Write a set of RPMH commands, the order of commands is maintained
+ * and will be sent as a single shot.
+ */
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ struct rpmh_request *rpm_msg;
+ int ret;
+
+ rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC);
+ if (!rpm_msg)
+ return -ENOMEM;
+ rpm_msg->needs_free = true;
+
+ ret = __fill_rpmh_msg(rpm_msg, state, cmd, n);
+ if (ret) {
+ kfree(rpm_msg);
+ return ret;
+ }
+
+ return __rpmh_write(dev, state, rpm_msg);
+}
+EXPORT_SYMBOL_GPL(rpmh_write_async);
+
+/**
+ * rpmh_write: Write a set of RPMH commands and block until response
+ *
+ * @dev: The device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The number of elements in @cmd
+ *
+ * May sleep. Do not call from atomic contexts.
+ */
+int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{
+ DECLARE_COMPLETION_ONSTACK(compl);
+ DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg);
+ int ret;
+
+ ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n);
+ if (ret)
+ return ret;
+
+ ret = __rpmh_write(dev, state, &rpm_msg);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
+ WARN_ON(!ret);
+ return (ret > 0) ? 0 : -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(rpmh_write);
+
+static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ list_add_tail(&req->list, &ctrlr->batch_cache);
+ ctrlr->dirty = true;
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+}
+
+static int flush_batch(struct rpmh_ctrlr *ctrlr)
+{
+ struct batch_cache_req *req;
+ const struct rpmh_request *rpm_msg;
+ int ret = 0;
+ int i;
+
+ /* Send Sleep/Wake requests to the controller, expect no response */
+ list_for_each_entry(req, &ctrlr->batch_cache, list) {
+ for (i = 0; i < req->count; i++) {
+ rpm_msg = req->rpm_msgs + i;
+ ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr),
+ &rpm_msg->msg);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
+ * batch to finish.
+ *
+ * @dev: the device making the request
+ * @state: Active/sleep set
+ * @cmd: The payload data
+ * @n: The array of count of elements in each batch, 0 terminated.
+ *
+ * Write a request to the RSC controller without caching. If the request
+ * state is ACTIVE, then the requests are treated as completion request
+ * and sent to the controller immediately. The function waits until all the
+ * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the
+ * request is sent as fire-n-forget and no ack is expected.
+ *
+ * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests.
+ */
+int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n)
+{
+ struct batch_cache_req *req;
+ struct rpmh_request *rpm_msgs;
+ struct completion *compls;
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ unsigned long time_left;
+ int count = 0;
+ int ret, i;
+ void *ptr;
+
+ if (!cmd || !n)
+ return -EINVAL;
+
+ while (n[count] > 0)
+ count++;
+ if (!count)
+ return -EINVAL;
+
+ ptr = kzalloc(sizeof(*req) +
+ count * (sizeof(req->rpm_msgs[0]) + sizeof(*compls)),
+ GFP_ATOMIC);
+ if (!ptr)
+ return -ENOMEM;
+
+ req = ptr;
+ compls = ptr + sizeof(*req) + count * sizeof(*rpm_msgs);
+
+ req->count = count;
+ rpm_msgs = req->rpm_msgs;
+
+ for (i = 0; i < count; i++) {
+ __fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]);
+ cmd += n[i];
+ }
+
+ if (state != RPMH_ACTIVE_ONLY_STATE) {
+ cache_batch(ctrlr, req);
+ return 0;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct completion *compl = &compls[i];
+
+ init_completion(compl);
+ rpm_msgs[i].completion = compl;
+ ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg);
+ if (ret) {
+ pr_err("Error(%d) sending RPMH message addr=%#x\n",
+ ret, rpm_msgs[i].msg.cmds[0].addr);
+ break;
+ }
+ }
+
+ time_left = RPMH_TIMEOUT_MS;
+ while (i--) {
+ time_left = wait_for_completion_timeout(&compls[i], time_left);
+ if (!time_left) {
+ /*
+ * Better hope they never finish because they'll signal
+ * the completion that we're going to free once
+ * we've returned from this function.
+ */
+ WARN_ON(1);
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ }
+
+exit:
+ kfree(ptr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rpmh_write_batch);
+
+static int is_req_valid(struct cache_req *req)
+{
+ return (req->sleep_val != UINT_MAX &&
+ req->wake_val != UINT_MAX &&
+ req->sleep_val != req->wake_val);
+}
+
+static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
+ u32 addr, u32 data)
+{
+ DEFINE_RPMH_MSG_ONSTACK(NULL, state, NULL, rpm_msg);
+
+ /* Wake sets are always complete and sleep sets are not */
+ rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE);
+ rpm_msg.cmd[0].addr = addr;
+ rpm_msg.cmd[0].data = data;
+ rpm_msg.msg.num_cmds = 1;
+
+ return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg);
+}
+
+/**
+ * rpmh_flush() - Flushes the buffered sleep and wake sets to TCSes
+ *
+ * @ctrlr: Controller making request to flush cached data
+ *
+ * Return:
+ * * 0 - Success
+ * * Error code - Otherwise
+ */
+int rpmh_flush(struct rpmh_ctrlr *ctrlr)
+{
+ struct cache_req *p;
+ int ret = 0;
+
+ lockdep_assert_irqs_disabled();
+
+ /*
+ * Currently rpmh_flush() is only called when we think we're running
+ * on the last processor. If the lock is busy it means another
+ * processor is up and it's better to abort than spin.
+ */
+ if (!spin_trylock(&ctrlr->cache_lock))
+ return -EBUSY;
+
+ if (!ctrlr->dirty) {
+ pr_debug("Skipping flush, TCS has latest data.\n");
+ goto write_next_wakeup;
+ }
+
+ /* Invalidate the TCSes first to avoid stale data */
+ rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
+
+ /* First flush the cached batch requests */
+ ret = flush_batch(ctrlr);
+ if (ret)
+ goto exit;
+
+ list_for_each_entry(p, &ctrlr->cache, list) {
+ if (!is_req_valid(p)) {
+ pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x",
+ __func__, p->addr, p->sleep_val, p->wake_val);
+ continue;
+ }
+ ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
+ p->sleep_val);
+ if (ret)
+ goto exit;
+ ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
+ p->wake_val);
+ if (ret)
+ goto exit;
+ }
+
+ ctrlr->dirty = false;
+
+write_next_wakeup:
+ rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr));
+exit:
+ spin_unlock(&ctrlr->cache_lock);
+ return ret;
+}
+
+/**
+ * rpmh_invalidate: Invalidate sleep and wake sets in batch_cache
+ *
+ * @dev: The device making the request
+ *
+ * Invalidate the sleep and wake values in batch_cache.
+ */
+void rpmh_invalidate(const struct device *dev)
+{
+ struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
+ struct batch_cache_req *req, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctrlr->cache_lock, flags);
+ list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
+ kfree(req);
+ INIT_LIST_HEAD(&ctrlr->batch_cache);
+ ctrlr->dirty = true;
+ spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
+}
+EXPORT_SYMBOL_GPL(rpmh_invalidate);
diff --git a/include/soc/qcom/cmd-db.h b/include/soc/qcom/cmd-db.h
new file mode 100644
index 000000000000..47a6cab75e63
--- /dev/null
+++ b/include/soc/qcom/cmd-db.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef __QCOM_COMMAND_DB_H__
+#define __QCOM_COMMAND_DB_H__
+
+#include <linux/err.h>
+
+enum cmd_db_hw_type {
+ CMD_DB_HW_INVALID = 0,
+ CMD_DB_HW_MIN = 3,
+ CMD_DB_HW_ARC = CMD_DB_HW_MIN,
+ CMD_DB_HW_VRM = 4,
+ CMD_DB_HW_BCM = 5,
+ CMD_DB_HW_MAX = CMD_DB_HW_BCM,
+ CMD_DB_HW_ALL = 0xff,
+};
+
+#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
+u32 cmd_db_read_addr(const char *resource_id);
+
+const void *cmd_db_read_aux_data(const char *resource_id, size_t *len);
+
+bool cmd_db_match_resource_addr(u32 addr1, u32 addr2);
+
+enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id);
+
+int cmd_db_ready(void);
+#else
+static inline u32 cmd_db_read_addr(const char *resource_id)
+{ return 0; }
+
+static inline const void *cmd_db_read_aux_data(const char *resource_id, size_t *len)
+{ return ERR_PTR(-ENODEV); }
+
+static inline bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
+{ return false; }
+
+static inline enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id)
+{ return -ENODEV; }
+
+static inline int cmd_db_ready(void)
+{ return -ENODEV; }
+#endif /* CONFIG_QCOM_COMMAND_DB */
+#endif /* __QCOM_COMMAND_DB_H__ */
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
new file mode 100644
index 000000000000..bdbee1a97d36
--- /dev/null
+++ b/include/soc/qcom/rpmh.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_QCOM_RPMH_H__
+#define __SOC_QCOM_RPMH_H__
+
+#include <soc/qcom/tcs.h>
+#include <linux/platform_device.h>
+
+
+#if IS_ENABLED(CONFIG_QCOM_RPMH)
+int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n);
+
+int rpmh_write_async(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n);
+
+int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n);
+
+void rpmh_invalidate(const struct device *dev);
+
+#else
+
+static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{ return -ENODEV; }
+
+static inline int rpmh_write_async(const struct device *dev,
+ enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 n)
+{ return -ENODEV; }
+
+static inline int rpmh_write_batch(const struct device *dev,
+ enum rpmh_state state,
+ const struct tcs_cmd *cmd, u32 *n)
+{ return -ENODEV; }
+
+static inline void rpmh_invalidate(const struct device *dev)
+{
+}
+
+#endif /* CONFIG_QCOM_RPMH */
+
+#endif /* __SOC_QCOM_RPMH_H__ */
diff --git a/include/soc/qcom/tcs.h b/include/soc/qcom/tcs.h
new file mode 100644
index 000000000000..3acca067c72b
--- /dev/null
+++ b/include/soc/qcom/tcs.h
@@ -0,0 +1,81 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ */
+
+#ifndef __SOC_QCOM_TCS_H__
+#define __SOC_QCOM_TCS_H__
+
+#define MAX_RPMH_PAYLOAD 16
+
+/**
+ * rpmh_state: state for the request
+ *
+ * RPMH_SLEEP_STATE: State of the resource when the processor subsystem
+ * is powered down. There is no client using the
+ * resource actively.
+ * RPMH_WAKE_ONLY_STATE: Resume resource state to the value previously
+ * requested before the processor was powered down.
+ * RPMH_ACTIVE_ONLY_STATE: Active or AMC mode requests. Resource state
+ * is aggregated immediately.
+ */
+enum rpmh_state {
+ RPMH_SLEEP_STATE,
+ RPMH_WAKE_ONLY_STATE,
+ RPMH_ACTIVE_ONLY_STATE,
+};
+
+/**
+ * struct tcs_cmd: an individual request to RPMH.
+ *
+ * @addr: the address of the resource slv_id:18:16 | offset:0:15
+ * @data: the resource state request
+ * @wait: ensure that this command is complete before returning.
+ * Setting "wait" here only makes sense during rpmh_write_batch() for
+ * active-only transfers, this is because:
+ * rpmh_write() - Always waits.
+ * (DEFINE_RPMH_MSG_ONSTACK will set .wait_for_compl)
+ * rpmh_write_async() - Never waits.
+ * (There's no request completion callback)
+ */
+struct tcs_cmd {
+ u32 addr;
+ u32 data;
+ u32 wait;
+};
+
+/**
+ * struct tcs_request: A set of tcs_cmds sent together in a TCS
+ *
+ * @state: state for the request.
+ * @wait_for_compl: wait until we get a response from the h/w accelerator
+ * (same as setting cmd->wait for all commands in the request)
+ * @num_cmds: the number of @cmds in this request
+ * @cmds: an array of tcs_cmds
+ */
+struct tcs_request {
+ enum rpmh_state state;
+ u32 wait_for_compl;
+ u32 num_cmds;
+ struct tcs_cmd *cmds;
+};
+
+#define BCM_TCS_CMD_COMMIT_SHFT 30
+#define BCM_TCS_CMD_COMMIT_MASK 0x40000000
+#define BCM_TCS_CMD_VALID_SHFT 29
+#define BCM_TCS_CMD_VALID_MASK 0x20000000
+#define BCM_TCS_CMD_VOTE_X_SHFT 14
+#define BCM_TCS_CMD_VOTE_MASK 0x3fff
+#define BCM_TCS_CMD_VOTE_Y_SHFT 0
+#define BCM_TCS_CMD_VOTE_Y_MASK 0xfffc000
+
+/* Construct a Bus Clock Manager (BCM) specific TCS command */
+#define BCM_TCS_CMD(commit, valid, vote_x, vote_y) \
+ (((commit) << BCM_TCS_CMD_COMMIT_SHFT) | \
+ ((valid) << BCM_TCS_CMD_VALID_SHFT) | \
+ ((cpu_to_le32(vote_x) & \
+ BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_X_SHFT) | \
+ ((cpu_to_le32(vote_y) & \
+ BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_Y_SHFT))
+
+#endif /* __SOC_QCOM_TCS_H__ */
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 04/24] soc: qcom: cmd-db: adjust headers for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (2 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 03/24] soc: qcom: import rpmh and cmd-db drivers from Linux Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 05/24] soc: qcom: cmd-db: drop unused functions Caleb Connolly
` (20 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Replace unused/unsupported Linux headers with appropriate U-Boot
alternatives.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/cmd-db.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index d84572662017..b25f3549c18f 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -3,18 +3,17 @@
* Copyright (c) 2016-2018, 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
-#include <linux/bitfield.h>
-#include <linux/debugfs.h>
+#define pr_fmt(fmt) "cmd-db: " fmt
+
+#include <dm.h>
+#include <dm/ofnode.h>
+#include <dm/device_compat.h>
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_reserved_mem.h>
-#include <linux/platform_device.h>
-#include <linux/seq_file.h>
#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/byteorder/generic.h>
#include <soc/qcom/cmd-db.h>
#define NUM_PRIORITY 2
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 05/24] soc: qcom: cmd-db: drop unused functions
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (3 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 04/24] soc: qcom: cmd-db: adjust headers for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot Caleb Connolly
` (19 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Due to our simpler rpmh-rsc driver and lack of debugfs, we don't need
quite a few cmd-db functions, just drop them.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/cmd-db.c | 144 ----------------------------------------------
include/soc/qcom/cmd-db.h | 15 -----
2 files changed, 159 deletions(-)
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index b25f3549c18f..4317310d0bcd 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -194,150 +194,8 @@ u32 cmd_db_read_addr(const char *id)
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
}
EXPORT_SYMBOL_GPL(cmd_db_read_addr);
-/**
- * cmd_db_read_aux_data() - Query command db for aux data.
- *
- * @id: Resource to retrieve AUX Data on
- * @len: size of data buffer returned
- *
- * Return: pointer to data on success, error pointer otherwise
- */
-const void *cmd_db_read_aux_data(const char *id, size_t *len)
-{
- int ret;
- const struct entry_header *ent;
- const struct rsc_hdr *rsc_hdr;
-
- ret = cmd_db_get_header(id, &ent, &rsc_hdr);
- if (ret)
- return ERR_PTR(ret);
-
- if (len)
- *len = le16_to_cpu(ent->len);
-
- return rsc_offset(rsc_hdr, ent);
-}
-EXPORT_SYMBOL_GPL(cmd_db_read_aux_data);
-
-/**
- * cmd_db_match_resource_addr() - Compare if both Resource addresses are same
- *
- * @addr1: Resource address to compare
- * @addr2: Resource address to compare
- *
- * Return: true if two addresses refer to the same resource, false otherwise
- */
-bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
-{
- /*
- * Each RPMh VRM accelerator resource has 3 or 4 contiguous 4-byte
- * aligned addresses associated with it. Ignore the offset to check
- * for VRM requests.
- */
- if (addr1 == addr2)
- return true;
- else if (SLAVE_ID(addr1) == CMD_DB_HW_VRM && VRM_ADDR(addr1) == VRM_ADDR(addr2))
- return true;
-
- return false;
-}
-EXPORT_SYMBOL_GPL(cmd_db_match_resource_addr);
-
-/**
- * cmd_db_read_slave_id - Get the slave ID for a given resource address
- *
- * @id: Resource id to query the DB for version
- *
- * Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error
- */
-enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
-{
- int ret;
- const struct entry_header *ent;
- u32 addr;
-
- ret = cmd_db_get_header(id, &ent, NULL);
- if (ret < 0)
- return CMD_DB_HW_INVALID;
-
- addr = le32_to_cpu(ent->addr);
- return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
-}
-EXPORT_SYMBOL_GPL(cmd_db_read_slave_id);
-
-#ifdef CONFIG_DEBUG_FS
-static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)
-{
- int i, j;
- const struct rsc_hdr *rsc;
- const struct entry_header *ent;
- const char *name;
- u16 len, version;
- u8 major, minor;
-
- seq_puts(seq, "Command DB DUMP\n");
-
- for (i = 0; i < MAX_SLV_ID; i++) {
- rsc = &cmd_db_header->header[i];
- if (!rsc->slv_id)
- break;
-
- switch (le16_to_cpu(rsc->slv_id)) {
- case CMD_DB_HW_ARC:
- name = "ARC";
- break;
- case CMD_DB_HW_VRM:
- name = "VRM";
- break;
- case CMD_DB_HW_BCM:
- name = "BCM";
- break;
- default:
- name = "Unknown";
- break;
- }
-
- version = le16_to_cpu(rsc->version);
- major = version >> 8;
- minor = version;
-
- seq_printf(seq, "Slave %s (v%u.%u)\n", name, major, minor);
- seq_puts(seq, "-------------------------\n");
-
- ent = rsc_to_entry_header(rsc);
- for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) {
- seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr),
- (int)strnlen(ent->id, sizeof(ent->id)), ent->id);
-
- len = le16_to_cpu(ent->len);
- if (len) {
- seq_printf(seq, " [%*ph]",
- len, rsc_offset(rsc, ent));
- }
- seq_putc(seq, '\n');
- }
- }
-
- return 0;
-}
-
-static int open_cmd_db_debugfs(struct inode *inode, struct file *file)
-{
- return single_open(file, cmd_db_debugfs_dump, inode->i_private);
-}
-#endif
-
-static const struct file_operations cmd_db_debugfs_ops = {
-#ifdef CONFIG_DEBUG_FS
- .open = open_cmd_db_debugfs,
-#endif
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int cmd_db_dev_probe(struct platform_device *pdev)
{
struct reserved_mem *rmem;
int ret = 0;
@@ -359,10 +217,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Invalid Command DB Magic\n");
return -EINVAL;
}
- debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
-
device_set_pm_not_required(&pdev->dev);
return 0;
}
diff --git a/include/soc/qcom/cmd-db.h b/include/soc/qcom/cmd-db.h
index 47a6cab75e63..753c7923f8e5 100644
--- a/include/soc/qcom/cmd-db.h
+++ b/include/soc/qcom/cmd-db.h
@@ -21,28 +21,13 @@ enum cmd_db_hw_type {
#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
u32 cmd_db_read_addr(const char *resource_id);
-const void *cmd_db_read_aux_data(const char *resource_id, size_t *len);
-
-bool cmd_db_match_resource_addr(u32 addr1, u32 addr2);
-
-enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id);
-
int cmd_db_ready(void);
#else
static inline u32 cmd_db_read_addr(const char *resource_id)
{ return 0; }
-static inline const void *cmd_db_read_aux_data(const char *resource_id, size_t *len)
-{ return ERR_PTR(-ENODEV); }
-
-static inline bool cmd_db_match_resource_addr(u32 addr1, u32 addr2)
-{ return false; }
-
-static inline enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id)
-{ return -ENODEV; }
-
static inline int cmd_db_ready(void)
{ return -ENODEV; }
#endif /* CONFIG_QCOM_COMMAND_DB */
#endif /* __QCOM_COMMAND_DB_H__ */
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (4 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 05/24] soc: qcom: cmd-db: drop unused functions Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 11:39 ` Simon Glass
2024-07-15 10:08 ` [PATCH v6 07/24] soc: qcom: cmd-db: adjust for U-Boot API Caleb Connolly
` (18 subsequent siblings)
24 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Integrate cmd-db into the U-Boot driver model.
This is just a wrapper around an in-memory database, so we just need to
get the address and validate that cmd-db is there.
Since cmd_db_header will be stored in the .data section we can skip
bind if it's already set.
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
To: Simon Glass <sjg@chromium.org>
---
drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
include/soc/qcom/cmd-db.h | 3 --
2 files changed, 23 insertions(+), 52 deletions(-)
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index 4317310d0bcd..f707aed59adf 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -105,9 +105,9 @@ static bool cmd_db_magic_matches(const struct cmd_db_header *header)
return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0;
}
-static struct cmd_db_header *cmd_db_header;
+static struct cmd_db_header *cmd_db_header __section(".data") = NULL;
static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr)
{
u16 offset = le16_to_cpu(hdr->header_offset);
@@ -123,24 +123,8 @@ rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent)
return cmd_db_header->data + offset + loffset;
}
-/**
- * cmd_db_ready - Indicates if command DB is available
- *
- * Return: 0 on success, errno otherwise
- */
-int cmd_db_ready(void)
-{
- if (cmd_db_header == NULL)
- return -EPROBE_DEFER;
- else if (!cmd_db_magic_matches(cmd_db_header))
- return -EINVAL;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(cmd_db_ready);
-
static int cmd_db_get_header(const char *id, const struct entry_header **eh,
const struct rsc_hdr **rh)
{
const struct rsc_hdr *rsc_hdr;
@@ -194,55 +178,45 @@ u32 cmd_db_read_addr(const char *id)
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
}
EXPORT_SYMBOL_GPL(cmd_db_read_addr);
-static int cmd_db_dev_probe(struct platform_device *pdev)
+int cmd_db_bind(struct udevice *dev)
{
- struct reserved_mem *rmem;
- int ret = 0;
+ void __iomem *base;
+ ofnode node;
- rmem = of_reserved_mem_lookup(pdev->dev.of_node);
- if (!rmem) {
- dev_err(&pdev->dev, "failed to acquire memory region\n");
- return -EINVAL;
- }
-
- cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
- if (!cmd_db_header) {
- ret = -ENOMEM;
- cmd_db_header = NULL;
- return ret;
+ if (cmd_db_header)
+ return 0;
+
+ node = dev_ofnode(dev);
+
+ debug("%s(%s)\n", __func__, ofnode_get_name(node));
+
+ base = (void __iomem *)ofnode_get_addr(node);
+ if ((fdt_addr_t)base == FDT_ADDR_T_NONE) {
+ log_err("%s: Failed to read base address\n", __func__);
+ return -ENOENT;
}
+ cmd_db_header = base;
if (!cmd_db_magic_matches(cmd_db_header)) {
- dev_err(&pdev->dev, "Invalid Command DB Magic\n");
+ log_err("%s: Invalid Command DB Magic\n", __func__);
return -EINVAL;
}
- device_set_pm_not_required(&pdev->dev);
-
return 0;
}
-static const struct of_device_id cmd_db_match_table[] = {
+static const struct udevice_id cmd_db_ids[] = {
{ .compatible = "qcom,cmd-db" },
{ }
};
-MODULE_DEVICE_TABLE(of, cmd_db_match_table);
-static struct platform_driver cmd_db_dev_driver = {
- .probe = cmd_db_dev_probe,
- .driver = {
- .name = "cmd-db",
- .of_match_table = cmd_db_match_table,
- .suppress_bind_attrs = true,
- },
+U_BOOT_DRIVER(qcom_cmd_db) = {
+ .name = "qcom_cmd_db",
+ .id = UCLASS_MISC,
+ .probe = cmd_db_bind,
+ .of_match = cmd_db_ids,
};
-static int __init cmd_db_device_init(void)
-{
- return platform_driver_register(&cmd_db_dev_driver);
-}
-core_initcall(cmd_db_device_init);
-
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver");
MODULE_LICENSE("GPL v2");
diff --git a/include/soc/qcom/cmd-db.h b/include/soc/qcom/cmd-db.h
index 753c7923f8e5..1190f2c22cab 100644
--- a/include/soc/qcom/cmd-db.h
+++ b/include/soc/qcom/cmd-db.h
@@ -21,13 +21,10 @@ enum cmd_db_hw_type {
#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
u32 cmd_db_read_addr(const char *resource_id);
-int cmd_db_ready(void);
#else
static inline u32 cmd_db_read_addr(const char *resource_id)
{ return 0; }
-static inline int cmd_db_ready(void)
-{ return -ENODEV; }
#endif /* CONFIG_QCOM_COMMAND_DB */
#endif /* __QCOM_COMMAND_DB_H__ */
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-15 10:08 ` [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot Caleb Connolly
@ 2024-07-15 11:39 ` Simon Glass
2024-07-15 21:42 ` Caleb Connolly
0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2024-07-15 11:39 UTC (permalink / raw)
To: Caleb Connolly
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
> Integrate cmd-db into the U-Boot driver model.
>
> This is just a wrapper around an in-memory database, so we just need to
> get the address and validate that cmd-db is there.
>
> Since cmd_db_header will be stored in the .data section we can skip
> bind if it's already set.
>
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
> To: Simon Glass <sjg@chromium.org>
> ---
> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
> include/soc/qcom/cmd-db.h | 3 --
> 2 files changed, 23 insertions(+), 52 deletions(-)
>
Reviewed-by: Simon Glass <sjg@chromium.org>
BTW, this is a MISC driver. Does it implement the read() operation?
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-15 11:39 ` Simon Glass
@ 2024-07-15 21:42 ` Caleb Connolly
2024-07-16 7:04 ` Simon Glass
0 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 21:42 UTC (permalink / raw)
To: Simon Glass
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
On 15/07/2024 13:39, Simon Glass wrote:
> On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>
>> Integrate cmd-db into the U-Boot driver model.
>>
>> This is just a wrapper around an in-memory database, so we just need to
>> get the address and validate that cmd-db is there.
>>
>> Since cmd_db_header will be stored in the .data section we can skip
>> bind if it's already set.
>>
>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
>> ---
>> To: Simon Glass <sjg@chromium.org>
>> ---
>> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
>> include/soc/qcom/cmd-db.h | 3 --
>> 2 files changed, 23 insertions(+), 52 deletions(-)
>>
>
> Reviewed-by: Simon Glass <sjg@chromium.org>
Thanks
>
> BTW, this is a MISC driver. Does it implement the read() operation?
No, the API (as defined in the header file) takes a string and returns a
database entry. cmd-db users don't have an easily available handle to
the node / udevice regardless.
--
// Caleb (they/them)
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-15 21:42 ` Caleb Connolly
@ 2024-07-16 7:04 ` Simon Glass
2024-07-16 7:16 ` Caleb Connolly
0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2024-07-16 7:04 UTC (permalink / raw)
To: Caleb Connolly
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
Hi Caleb,
On Mon, 15 Jul 2024 at 22:42, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
>
>
> On 15/07/2024 13:39, Simon Glass wrote:
> > On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>
> >> Integrate cmd-db into the U-Boot driver model.
> >>
> >> This is just a wrapper around an in-memory database, so we just need to
> >> get the address and validate that cmd-db is there.
> >>
> >> Since cmd_db_header will be stored in the .data section we can skip
> >> bind if it's already set.
> >>
> >> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> >> ---
> >> To: Simon Glass <sjg@chromium.org>
> >> ---
> >> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
> >> include/soc/qcom/cmd-db.h | 3 --
> >> 2 files changed, 23 insertions(+), 52 deletions(-)
> >>
> >
> > Reviewed-by: Simon Glass <sjg@chromium.org>
>
> Thanks
> >
> > BTW, this is a MISC driver. Does it implement the read() operation?
>
> No, the API (as defined in the header file) takes a string and returns a
> database entry. cmd-db users don't have an easily available handle to
> the node / udevice regardless.
OK. The closest thing might be UCLASS_SYSINFO, but it is designed for
inside U-Boot and uses an int instead of a string for lookup.
Could you use the devicetree for this information? What sort of info is it?
Regards,
Simon
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-16 7:04 ` Simon Glass
@ 2024-07-16 7:16 ` Caleb Connolly
2024-07-19 15:04 ` Simon Glass
0 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-16 7:16 UTC (permalink / raw)
To: Simon Glass
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
On 16/07/2024 09:04, Simon Glass wrote:
> Hi Caleb,
>
> On Mon, 15 Jul 2024 at 22:42, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>
>>
>>
>> On 15/07/2024 13:39, Simon Glass wrote:
>>> On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>>>
>>>> Integrate cmd-db into the U-Boot driver model.
>>>>
>>>> This is just a wrapper around an in-memory database, so we just need to
>>>> get the address and validate that cmd-db is there.
>>>>
>>>> Since cmd_db_header will be stored in the .data section we can skip
>>>> bind if it's already set.
>>>>
>>>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
>>>> ---
>>>> To: Simon Glass <sjg@chromium.org>
>>>> ---
>>>> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
>>>> include/soc/qcom/cmd-db.h | 3 --
>>>> 2 files changed, 23 insertions(+), 52 deletions(-)
>>>>
>>>
>>> Reviewed-by: Simon Glass <sjg@chromium.org>
>>
>> Thanks
>>>
>>> BTW, this is a MISC driver. Does it implement the read() operation?
>>
>> No, the API (as defined in the header file) takes a string and returns a
>> database entry. cmd-db users don't have an easily available handle to
>> the node / udevice regardless.
>
> OK. The closest thing might be UCLASS_SYSINFO, but it is designed for
> inside U-Boot and uses an int instead of a string for lookup.
Right, I don't think we'll be able to find a more optimum solution here.
>
> Could you use the devicetree for this information? What sort of info is it?
It maps resource names (e.g. "ldoa1" - the LDO1 regulator on PMIC A) to
the address of the resource on the RPMh co-processor.
We need to support existing (upstream) devicetree, since this has
already been around for many years.
>
> Regards,
> Simon
--
// Caleb (they/them)
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-16 7:16 ` Caleb Connolly
@ 2024-07-19 15:04 ` Simon Glass
2024-07-19 19:45 ` Caleb Connolly
0 siblings, 1 reply; 36+ messages in thread
From: Simon Glass @ 2024-07-19 15:04 UTC (permalink / raw)
To: Caleb Connolly
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
Hi Caleb,
On Tue, 16 Jul 2024 at 08:16, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
>
>
> On 16/07/2024 09:04, Simon Glass wrote:
> > Hi Caleb,
> >
> > On Mon, 15 Jul 2024 at 22:42, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>
> >>
> >>
> >> On 15/07/2024 13:39, Simon Glass wrote:
> >>> On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>>>
> >>>> Integrate cmd-db into the U-Boot driver model.
> >>>>
> >>>> This is just a wrapper around an in-memory database, so we just need to
> >>>> get the address and validate that cmd-db is there.
> >>>>
> >>>> Since cmd_db_header will be stored in the .data section we can skip
> >>>> bind if it's already set.
> >>>>
> >>>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> >>>> ---
> >>>> To: Simon Glass <sjg@chromium.org>
> >>>> ---
> >>>> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
> >>>> include/soc/qcom/cmd-db.h | 3 --
> >>>> 2 files changed, 23 insertions(+), 52 deletions(-)
> >>>>
> >>>
> >>> Reviewed-by: Simon Glass <sjg@chromium.org>
> >>
> >> Thanks
> >>>
> >>> BTW, this is a MISC driver. Does it implement the read() operation?
> >>
> >> No, the API (as defined in the header file) takes a string and returns a
> >> database entry. cmd-db users don't have an easily available handle to
> >> the node / udevice regardless.
> >
> > OK. The closest thing might be UCLASS_SYSINFO, but it is designed for
> > inside U-Boot and uses an int instead of a string for lookup.
>
> Right, I don't think we'll be able to find a more optimum solution here.
OK
> >
> > Could you use the devicetree for this information? What sort of info is it?
>
> It maps resource names (e.g. "ldoa1" - the LDO1 regulator on PMIC A) to
> the address of the resource on the RPMh co-processor.
>
> We need to support existing (upstream) devicetree, since this has
> already been around for many years.
OK., Has this problem been resolved in more recent platforms?
Regards,
Simon
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-19 15:04 ` Simon Glass
@ 2024-07-19 19:45 ` Caleb Connolly
2024-07-20 12:36 ` Simon Glass
0 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-19 19:45 UTC (permalink / raw)
To: Simon Glass
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
On 19/07/2024 17:04, Simon Glass wrote:
> Hi Caleb,
>
> On Tue, 16 Jul 2024 at 08:16, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>
>>
>>
>> On 16/07/2024 09:04, Simon Glass wrote:
>>> Hi Caleb,
>>>
>>> On Mon, 15 Jul 2024 at 22:42, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>>>
>>>>
>>>>
>>>> On 15/07/2024 13:39, Simon Glass wrote:
>>>>> On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>>>>>>
>>>>>> Integrate cmd-db into the U-Boot driver model.
>>>>>>
>>>>>> This is just a wrapper around an in-memory database, so we just need to
>>>>>> get the address and validate that cmd-db is there.
>>>>>>
>>>>>> Since cmd_db_header will be stored in the .data section we can skip
>>>>>> bind if it's already set.
>>>>>>
>>>>>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
>>>>>> ---
>>>>>> To: Simon Glass <sjg@chromium.org>
>>>>>> ---
>>>>>> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
>>>>>> include/soc/qcom/cmd-db.h | 3 --
>>>>>> 2 files changed, 23 insertions(+), 52 deletions(-)
>>>>>>
>>>>>
>>>>> Reviewed-by: Simon Glass <sjg@chromium.org>
>>>>
>>>> Thanks
>>>>>
>>>>> BTW, this is a MISC driver. Does it implement the read() operation?
>>>>
>>>> No, the API (as defined in the header file) takes a string and returns a
>>>> database entry. cmd-db users don't have an easily available handle to
>>>> the node / udevice regardless.
>>>
>>> OK. The closest thing might be UCLASS_SYSINFO, but it is designed for
>>> inside U-Boot and uses an int instead of a string for lookup.
>>
>> Right, I don't think we'll be able to find a more optimum solution here.
>
> OK
>
>>>
>>> Could you use the devicetree for this information? What sort of info is it?
>>
>> It maps resource names (e.g. "ldoa1" - the LDO1 regulator on PMIC A) to
>> the address of the resource on the RPMh co-processor.
>>
>> We need to support existing (upstream) devicetree, since this has
>> already been around for many years.
>
> OK., Has this problem been resolved in more recent platforms?
What problem?
>
> Regards,
> Simon
--
// Caleb (they/them)
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot
2024-07-19 19:45 ` Caleb Connolly
@ 2024-07-20 12:36 ` Simon Glass
0 siblings, 0 replies; 36+ messages in thread
From: Simon Glass @ 2024-07-20 12:36 UTC (permalink / raw)
To: Caleb Connolly
Cc: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, u-boot,
u-boot-qcom
Hi Caleb,
On Fri, 19 Jul 2024 at 20:45, Caleb Connolly <caleb.connolly@linaro.org> wrote:
>
>
>
> On 19/07/2024 17:04, Simon Glass wrote:
> > Hi Caleb,
> >
> > On Tue, 16 Jul 2024 at 08:16, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>
> >>
> >>
> >> On 16/07/2024 09:04, Simon Glass wrote:
> >>> Hi Caleb,
> >>>
> >>> On Mon, 15 Jul 2024 at 22:42, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>>>
> >>>>
> >>>>
> >>>> On 15/07/2024 13:39, Simon Glass wrote:
> >>>>> On Mon, 15 Jul 2024 at 11:08, Caleb Connolly <caleb.connolly@linaro.org> wrote:
> >>>>>>
> >>>>>> Integrate cmd-db into the U-Boot driver model.
> >>>>>>
> >>>>>> This is just a wrapper around an in-memory database, so we just need to
> >>>>>> get the address and validate that cmd-db is there.
> >>>>>>
> >>>>>> Since cmd_db_header will be stored in the .data section we can skip
> >>>>>> bind if it's already set.
> >>>>>>
> >>>>>> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> >>>>>> ---
> >>>>>> To: Simon Glass <sjg@chromium.org>
> >>>>>> ---
> >>>>>> drivers/soc/qcom/cmd-db.c | 72 +++++++++++++++--------------------------------
> >>>>>> include/soc/qcom/cmd-db.h | 3 --
> >>>>>> 2 files changed, 23 insertions(+), 52 deletions(-)
> >>>>>>
> >>>>>
> >>>>> Reviewed-by: Simon Glass <sjg@chromium.org>
> >>>>
> >>>> Thanks
> >>>>>
> >>>>> BTW, this is a MISC driver. Does it implement the read() operation?
> >>>>
> >>>> No, the API (as defined in the header file) takes a string and returns a
> >>>> database entry. cmd-db users don't have an easily available handle to
> >>>> the node / udevice regardless.
> >>>
> >>> OK. The closest thing might be UCLASS_SYSINFO, but it is designed for
> >>> inside U-Boot and uses an int instead of a string for lookup.
> >>
> >> Right, I don't think we'll be able to find a more optimum solution here.
> >
> > OK
> >
> >>>
> >>> Could you use the devicetree for this information? What sort of info is it?
> >>
> >> It maps resource names (e.g. "ldoa1" - the LDO1 regulator on PMIC A) to
> >> the address of the resource on the RPMh co-processor.
> >>
> >> We need to support existing (upstream) devicetree, since this has
> >> already been around for many years.
> >
> > OK., Has this problem been resolved in more recent platforms?
>
> What problem?
Well it sounds like the board is using some sort of firmware service
to obtain configuration when it should be using the devicetree. Is
that right?
Regards,
Simon
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v6 07/24] soc: qcom: cmd-db: adjust for U-Boot API
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (5 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 06/24] soc: qcom: cmd-db: adjust probe for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 08/24] soc: qcom: rpmh-rsc: drop unused multi-threading and non-active TCS support Caleb Connolly
` (17 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Keep the header pointer in the .data section so we don't initialize it
again after relocation, adjust cmd_db_get_header() to work with the
U-Boot API, and skip validating the header since all cmd-db users are
children of the rpmh-rsc and those children will only probe if cmd-db
initializes successfully.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/cmd-db.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c
index f707aed59adf..08736ea936ae 100644
--- a/drivers/soc/qcom/cmd-db.c
+++ b/drivers/soc/qcom/cmd-db.c
@@ -128,16 +128,12 @@ static int cmd_db_get_header(const char *id, const struct entry_header **eh,
const struct rsc_hdr **rh)
{
const struct rsc_hdr *rsc_hdr;
const struct entry_header *ent;
- int ret, i, j;
+ int i, j;
u8 query[sizeof(ent->id)] __nonstring;
- ret = cmd_db_ready();
- if (ret)
- return ret;
-
- strtomem_pad(query, id, 0);
+ strncpy(query, id, sizeof(query));
for (i = 0; i < MAX_SLV_ID; i++) {
rsc_hdr = &cmd_db_header->header[i];
if (!rsc_hdr->slv_id)
@@ -172,8 +168,15 @@ u32 cmd_db_read_addr(const char *id)
{
int ret;
const struct entry_header *ent;
+ debug("%s(%s)\n", __func__, id);
+
+ if (!cmd_db_header) {
+ log_err("%s: Command DB not initialized\n", __func__);
+ return 0;
+ }
+
ret = cmd_db_get_header(id, &ent, NULL);
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
}
@@ -213,9 +216,9 @@ static const struct udevice_id cmd_db_ids[] = {
U_BOOT_DRIVER(qcom_cmd_db) = {
.name = "qcom_cmd_db",
.id = UCLASS_MISC,
- .probe = cmd_db_bind,
+ .bind = cmd_db_bind,
.of_match = cmd_db_ids,
};
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. Command DB Driver");
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 08/24] soc: qcom: rpmh-rsc: drop unused multi-threading and non-active TCS support
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (6 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 07/24] soc: qcom: cmd-db: adjust for U-Boot API Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 09/24] soc: qcom: rpmh-rsc: adjust headers for U-Boot Caleb Connolly
` (16 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Since U-Boot is single threaded, we can avoid most of the complexity
that comes with handling more than one in-flight TCS. Drop all the rpmh
code associated with multi-threading as we'll instead wait for a
response on each TCS.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh-internal.h | 4 -
drivers/soc/qcom/rpmh-rsc.c | 562 ---------------------------------------
2 files changed, 566 deletions(-)
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index e3cf1beff803..12c5b8d9cf86 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -139,10 +139,6 @@ struct rsc_drv {
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
const struct tcs_request *msg);
void rpmh_rsc_invalidate(struct rsc_drv *drv);
-void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv);
-
-void rpmh_tx_done(const struct tcs_request *msg);
-int rpmh_flush(struct rpmh_ctrlr *ctrlr);
#endif /* __RPM_INTERNAL_H__ */
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index de86009ecd91..fc8321bf208f 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -246,49 +246,8 @@ static void write_tcs_reg_sync(const struct rsc_drv *drv, int reg, int tcs_id,
pr_err("%s: error writing %#x to %d:%#x\n", drv->name,
data, tcs_id, reg);
}
-/**
- * tcs_invalidate() - Invalidate all TCSes of the given type (sleep or wake).
- * @drv: The RSC controller.
- * @type: SLEEP_TCS or WAKE_TCS
- *
- * This will clear the "slots" variable of the given tcs_group and also
- * tell the hardware to forget about all entries.
- *
- * The caller must ensure that no other RPMH actions are happening when this
- * function is called, since otherwise the device may immediately become
- * used again even before this function exits.
- */
-static void tcs_invalidate(struct rsc_drv *drv, int type)
-{
- int m;
- struct tcs_group *tcs = &drv->tcs[type];
-
- /* Caller ensures nobody else is running so no lock */
- if (bitmap_empty(tcs->slots, MAX_TCS_SLOTS))
- return;
-
- for (m = tcs->offset; m < tcs->offset + tcs->num_tcs; m++)
- write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], m, 0);
-
- bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
-}
-
-/**
- * rpmh_rsc_invalidate() - Invalidate sleep and wake TCSes.
- * @drv: The RSC controller.
- *
- * The caller must ensure that no other RPMH actions are happening when this
- * function is called, since otherwise the device may immediately become
- * used again even before this function exits.
- */
-void rpmh_rsc_invalidate(struct rsc_drv *drv)
-{
- tcs_invalidate(drv, SLEEP_TCS);
- tcs_invalidate(drv, WAKE_TCS);
-}
-
/**
* get_tcs_for_msg() - Get the tcs_group used to send the given message.
* @drv: The RSC controller.
* @msg: The message we want to send.
@@ -331,158 +290,8 @@ static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
return tcs;
}
-/**
- * get_req_from_tcs() - Get a stashed request that was xfering on the given TCS.
- * @drv: The RSC controller.
- * @tcs_id: The global ID of this TCS.
- *
- * For ACTIVE_ONLY transfers we want to call back into the client when the
- * transfer finishes. To do this we need the "request" that the client
- * originally provided us. This function grabs the request that we stashed
- * when we started the transfer.
- *
- * This only makes sense for ACTIVE_ONLY transfers since those are the only
- * ones we track sending (the only ones we enable interrupts for and the only
- * ones we call back to the client for).
- *
- * Return: The stashed request.
- */
-static const struct tcs_request *get_req_from_tcs(struct rsc_drv *drv,
- int tcs_id)
-{
- struct tcs_group *tcs;
- int i;
-
- for (i = 0; i < TCS_TYPE_NR; i++) {
- tcs = &drv->tcs[i];
- if (tcs->mask & BIT(tcs_id))
- return tcs->req[tcs_id - tcs->offset];
- }
-
- return NULL;
-}
-
-/**
- * __tcs_set_trigger() - Start xfer on a TCS or unset trigger on a borrowed TCS
- * @drv: The controller.
- * @tcs_id: The global ID of this TCS.
- * @trigger: If true then untrigger/retrigger. If false then just untrigger.
- *
- * In the normal case we only ever call with "trigger=true" to start a
- * transfer. That will un-trigger/disable the TCS from the last transfer
- * then trigger/enable for this transfer.
- *
- * If we borrowed a wake TCS for an active-only transfer we'll also call
- * this function with "trigger=false" to just do the un-trigger/disable
- * before using the TCS for wake purposes again.
- *
- * Note that the AP is only in charge of triggering active-only transfers.
- * The AP never triggers sleep/wake values using this function.
- */
-static void __tcs_set_trigger(struct rsc_drv *drv, int tcs_id, bool trigger)
-{
- u32 enable;
- u32 reg = drv->regs[RSC_DRV_CONTROL];
-
- /*
- * HW req: Clear the DRV_CONTROL and enable TCS again
- * While clearing ensure that the AMC mode trigger is cleared
- * and then the mode enable is cleared.
- */
- enable = read_tcs_reg(drv, reg, tcs_id);
- enable &= ~TCS_AMC_MODE_TRIGGER;
- write_tcs_reg_sync(drv, reg, tcs_id, enable);
- enable &= ~TCS_AMC_MODE_ENABLE;
- write_tcs_reg_sync(drv, reg, tcs_id, enable);
-
- if (trigger) {
- /* Enable the AMC mode on the TCS and then trigger the TCS */
- enable = TCS_AMC_MODE_ENABLE;
- write_tcs_reg_sync(drv, reg, tcs_id, enable);
- enable |= TCS_AMC_MODE_TRIGGER;
- write_tcs_reg(drv, reg, tcs_id, enable);
- }
-}
-
-/**
- * enable_tcs_irq() - Enable or disable interrupts on the given TCS.
- * @drv: The controller.
- * @tcs_id: The global ID of this TCS.
- * @enable: If true then enable; if false then disable
- *
- * We only ever call this when we borrow a wake TCS for an active-only
- * transfer. For active-only TCSes interrupts are always left enabled.
- */
-static void enable_tcs_irq(struct rsc_drv *drv, int tcs_id, bool enable)
-{
- u32 data;
- u32 reg = drv->regs[RSC_DRV_IRQ_ENABLE];
-
- data = readl_relaxed(drv->tcs_base + reg);
- if (enable)
- data |= BIT(tcs_id);
- else
- data &= ~BIT(tcs_id);
- writel_relaxed(data, drv->tcs_base + reg);
-}
-
-/**
- * tcs_tx_done() - TX Done interrupt handler.
- * @irq: The IRQ number (ignored).
- * @p: Pointer to "struct rsc_drv".
- *
- * Called for ACTIVE_ONLY transfers (those are the only ones we enable the
- * IRQ for) when a transfer is done.
- *
- * Return: IRQ_HANDLED
- */
-static irqreturn_t tcs_tx_done(int irq, void *p)
-{
- struct rsc_drv *drv = p;
- int i;
- unsigned long irq_status;
- const struct tcs_request *req;
-
- irq_status = readl_relaxed(drv->tcs_base + drv->regs[RSC_DRV_IRQ_STATUS]);
-
- for_each_set_bit(i, &irq_status, BITS_PER_TYPE(u32)) {
- req = get_req_from_tcs(drv, i);
- if (WARN_ON(!req))
- goto skip;
-
- trace_rpmh_tx_done(drv, i, req);
-
- /*
- * If wake tcs was re-purposed for sending active
- * votes, clear AMC trigger & enable modes and
- * disable interrupt for this TCS
- */
- if (!drv->tcs[ACTIVE_TCS].num_tcs)
- __tcs_set_trigger(drv, i, false);
-skip:
- /* Reclaim the TCS */
- write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i, 0);
- writel_relaxed(BIT(i), drv->tcs_base + drv->regs[RSC_DRV_IRQ_CLEAR]);
- spin_lock(&drv->lock);
- clear_bit(i, drv->tcs_in_use);
- /*
- * Disable interrupt for WAKE TCS to avoid being
- * spammed with interrupts coming when the solver
- * sends its wake votes.
- */
- if (!drv->tcs[ACTIVE_TCS].num_tcs)
- enable_tcs_irq(drv, i, false);
- spin_unlock(&drv->lock);
- wake_up(&drv->tcs_wait);
- if (req)
- rpmh_tx_done(req);
- }
-
- return IRQ_HANDLED;
-}
-
/**
* __tcs_buffer_write() - Write to TCS hardware from a request; don't trigger.
* @drv: The controller.
* @tcs_id: The global ID of this TCS.
@@ -523,104 +332,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
}
-/**
- * check_for_req_inflight() - Look to see if conflicting cmds are in flight.
- * @drv: The controller.
- * @tcs: A pointer to the tcs_group used for ACTIVE_ONLY transfers.
- * @msg: The message we want to send, which will contain several addr/data
- * pairs to program (but few enough that they all fit in one TCS).
- *
- * This will walk through the TCSes in the group and check if any of them
- * appear to be sending to addresses referenced in the message. If it finds
- * one it'll return -EBUSY.
- *
- * Only for use for active-only transfers.
- *
- * Must be called with the drv->lock held since that protects tcs_in_use.
- *
- * Return: 0 if nothing in flight or -EBUSY if we should try again later.
- * The caller must re-enable interrupts between tries since that's
- * the only way tcs_in_use will ever be updated and the only way
- * RSC_DRV_CMD_ENABLE will ever be cleared.
- */
-static int check_for_req_inflight(struct rsc_drv *drv, struct tcs_group *tcs,
- const struct tcs_request *msg)
-{
- unsigned long curr_enabled;
- u32 addr;
- int j, k;
- int i = tcs->offset;
-
- for_each_set_bit_from(i, drv->tcs_in_use, tcs->offset + tcs->num_tcs) {
- curr_enabled = read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], i);
-
- for_each_set_bit(j, &curr_enabled, MAX_CMDS_PER_TCS) {
- addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, j);
- for (k = 0; k < msg->num_cmds; k++) {
- if (cmd_db_match_resource_addr(msg->cmds[k].addr, addr))
- return -EBUSY;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * find_free_tcs() - Find free tcs in the given tcs_group; only for active.
- * @tcs: A pointer to the active-only tcs_group (or the wake tcs_group if
- * we borrowed it because there are zero active-only ones).
- *
- * Must be called with the drv->lock held since that protects tcs_in_use.
- *
- * Return: The first tcs that's free or -EBUSY if all in use.
- */
-static int find_free_tcs(struct tcs_group *tcs)
-{
- const struct rsc_drv *drv = tcs->drv;
- unsigned long i;
- unsigned long max = tcs->offset + tcs->num_tcs;
-
- i = find_next_zero_bit(drv->tcs_in_use, max, tcs->offset);
- if (i >= max)
- return -EBUSY;
-
- return i;
-}
-
-/**
- * claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active.
- * @drv: The controller.
- * @tcs: The tcs_group used for ACTIVE_ONLY transfers.
- * @msg: The data to be sent.
- *
- * Claims a tcs in the given tcs_group while making sure that no existing cmd
- * is in flight that would conflict with the one in @msg.
- *
- * Context: Must be called with the drv->lock held since that protects
- * tcs_in_use.
- *
- * Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight
- * or the tcs_group is full.
- */
-static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs,
- const struct tcs_request *msg)
-{
- int ret;
-
- /*
- * The h/w does not like if we send a request to the same address,
- * when one is already in-flight or being processed.
- */
- ret = check_for_req_inflight(drv, tcs, msg);
- if (ret)
- return ret;
-
- return find_free_tcs(tcs);
-}
-
/**
* rpmh_rsc_send_data() - Write / trigger active-only message.
* @drv: The controller.
* @msg: The data to be sent.
@@ -668,9 +381,8 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* repurposed TCS to avoid triggering them. tcs->slots will be
* cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
*/
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
- enable_tcs_irq(drv, tcs_id, true);
}
spin_unlock_irq(&drv->lock);
/*
@@ -681,286 +393,12 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* - The interrupt can't go off until we trigger w/ the last line
* of __tcs_set_trigger() below.
*/
__tcs_buffer_write(drv, tcs_id, 0, msg);
- __tcs_set_trigger(drv, tcs_id, true);
return 0;
}
-/**
- * find_slots() - Find a place to write the given message.
- * @tcs: The tcs group to search.
- * @msg: The message we want to find room for.
- * @tcs_id: If we return 0 from the function, we return the global ID of the
- * TCS to write to here.
- * @cmd_id: If we return 0 from the function, we return the index of
- * the command array of the returned TCS where the client should
- * start writing the message.
- *
- * Only for use on sleep/wake TCSes since those are the only ones we maintain
- * tcs->slots for.
- *
- * Return: -ENOMEM if there was no room, else 0.
- */
-static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
- int *tcs_id, int *cmd_id)
-{
- int slot, offset;
- int i = 0;
-
- /* Do over, until we can fit the full payload in a single TCS */
- do {
- slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
- i, msg->num_cmds, 0);
- if (slot >= tcs->num_tcs * tcs->ncpt)
- return -ENOMEM;
- i += tcs->ncpt;
- } while (slot + msg->num_cmds - 1 >= i);
-
- bitmap_set(tcs->slots, slot, msg->num_cmds);
-
- offset = slot / tcs->ncpt;
- *tcs_id = offset + tcs->offset;
- *cmd_id = slot % tcs->ncpt;
-
- return 0;
-}
-
-/**
- * rpmh_rsc_write_ctrl_data() - Write request to controller but don't trigger.
- * @drv: The controller.
- * @msg: The data to be written to the controller.
- *
- * This should only be called for sleep/wake state, never active-only
- * state.
- *
- * The caller must ensure that no other RPMH actions are happening and the
- * controller is idle when this function is called since it runs lockless.
- *
- * Return: 0 if no error; else -error.
- */
-int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, const struct tcs_request *msg)
-{
- struct tcs_group *tcs;
- int tcs_id = 0, cmd_id = 0;
- int ret;
-
- tcs = get_tcs_for_msg(drv, msg);
- if (IS_ERR(tcs))
- return PTR_ERR(tcs);
-
- /* find the TCS id and the command in the TCS to write to */
- ret = find_slots(tcs, msg, &tcs_id, &cmd_id);
- if (!ret)
- __tcs_buffer_write(drv, tcs_id, cmd_id, msg);
-
- return ret;
-}
-
-/**
- * rpmh_rsc_ctrlr_is_busy() - Check if any of the AMCs are busy.
- * @drv: The controller
- *
- * Checks if any of the AMCs are busy in handling ACTIVE sets.
- * This is called from the last cpu powering down before flushing
- * SLEEP and WAKE sets. If AMCs are busy, controller can not enter
- * power collapse, so deny from the last cpu's pm notification.
- *
- * Context: Must be called with the drv->lock held.
- *
- * Return:
- * * False - AMCs are idle
- * * True - AMCs are busy
- */
-static bool rpmh_rsc_ctrlr_is_busy(struct rsc_drv *drv)
-{
- unsigned long set;
- const struct tcs_group *tcs = &drv->tcs[ACTIVE_TCS];
- unsigned long max;
-
- /*
- * If we made an active request on a RSC that does not have a
- * dedicated TCS for active state use, then re-purposed wake TCSes
- * should be checked for not busy, because we used wake TCSes for
- * active requests in this case.
- */
- if (!tcs->num_tcs)
- tcs = &drv->tcs[WAKE_TCS];
-
- max = tcs->offset + tcs->num_tcs;
- set = find_next_bit(drv->tcs_in_use, max, tcs->offset);
-
- return set < max;
-}
-
-/**
- * rpmh_rsc_write_next_wakeup() - Write next wakeup in CONTROL_TCS.
- * @drv: The controller
- *
- * Writes maximum wakeup cycles when called from suspend.
- * Writes earliest hrtimer wakeup when called from idle.
- */
-void rpmh_rsc_write_next_wakeup(struct rsc_drv *drv)
-{
- ktime_t now, wakeup;
- u64 wakeup_us, wakeup_cycles = ~0;
- u32 lo, hi;
-
- if (!drv->tcs[CONTROL_TCS].num_tcs || !drv->genpd_nb.notifier_call)
- return;
-
- /* Set highest time when system (timekeeping) is suspended */
- if (system_state == SYSTEM_SUSPEND)
- goto exit;
-
- /* Find the earliest hrtimer wakeup from online cpus */
- wakeup = dev_pm_genpd_get_next_hrtimer(drv->dev);
-
- /* Find the relative wakeup in kernel time scale */
- now = ktime_get();
- wakeup = ktime_sub(wakeup, now);
- wakeup_us = ktime_to_us(wakeup);
-
- /* Convert the wakeup to arch timer scale */
- wakeup_cycles = USECS_TO_CYCLES(wakeup_us);
- wakeup_cycles += arch_timer_read_counter();
-
-exit:
- lo = wakeup_cycles & RSC_DRV_CTL_TCS_DATA_LO_MASK;
- hi = wakeup_cycles >> RSC_DRV_CTL_TCS_DATA_SIZE;
- hi &= RSC_DRV_CTL_TCS_DATA_HI_MASK;
- hi |= RSC_DRV_CTL_TCS_DATA_HI_VALID;
-
- writel_relaxed(lo, drv->base + RSC_DRV_CTL_TCS_DATA_LO);
- writel_relaxed(hi, drv->base + RSC_DRV_CTL_TCS_DATA_HI);
-}
-
-/**
- * rpmh_rsc_cpu_pm_callback() - Check if any of the AMCs are busy.
- * @nfb: Pointer to the notifier block in struct rsc_drv.
- * @action: CPU_PM_ENTER, CPU_PM_ENTER_FAILED, or CPU_PM_EXIT.
- * @v: Unused
- *
- * This function is given to cpu_pm_register_notifier so we can be informed
- * about when CPUs go down. When all CPUs go down we know no more active
- * transfers will be started so we write sleep/wake sets. This function gets
- * called from cpuidle code paths and also at system suspend time.
- *
- * If its last CPU going down and AMCs are not busy then writes cached sleep
- * and wake messages to TCSes. The firmware then takes care of triggering
- * them when entering deepest low power modes.
- *
- * Return: See cpu_pm_register_notifier()
- */
-static int rpmh_rsc_cpu_pm_callback(struct notifier_block *nfb,
- unsigned long action, void *v)
-{
- struct rsc_drv *drv = container_of(nfb, struct rsc_drv, rsc_pm);
- int ret = NOTIFY_OK;
- int cpus_in_pm;
-
- switch (action) {
- case CPU_PM_ENTER:
- cpus_in_pm = atomic_inc_return(&drv->cpus_in_pm);
- /*
- * NOTE: comments for num_online_cpus() point out that it's
- * only a snapshot so we need to be careful. It should be OK
- * for us to use, though. It's important for us not to miss
- * if we're the last CPU going down so it would only be a
- * problem if a CPU went offline right after we did the check
- * AND that CPU was not idle AND that CPU was the last non-idle
- * CPU. That can't happen. CPUs would have to come out of idle
- * before the CPU could go offline.
- */
- if (cpus_in_pm < num_online_cpus())
- return NOTIFY_OK;
- break;
- case CPU_PM_ENTER_FAILED:
- case CPU_PM_EXIT:
- atomic_dec(&drv->cpus_in_pm);
- return NOTIFY_OK;
- default:
- return NOTIFY_DONE;
- }
-
- /*
- * It's likely we're on the last CPU. Grab the drv->lock and write
- * out the sleep/wake commands to RPMH hardware. Grabbing the lock
- * means that if we race with another CPU coming up we are still
- * guaranteed to be safe. If another CPU came up just after we checked
- * and has grabbed the lock or started an active transfer then we'll
- * notice we're busy and abort. If another CPU comes up after we start
- * flushing it will be blocked from starting an active transfer until
- * we're done flushing. If another CPU starts an active transfer after
- * we release the lock we're still OK because we're no longer the last
- * CPU.
- */
- if (spin_trylock(&drv->lock)) {
- if (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client))
- ret = NOTIFY_BAD;
- spin_unlock(&drv->lock);
- } else {
- /* Another CPU must be up */
- return NOTIFY_OK;
- }
-
- if (ret == NOTIFY_BAD) {
- /* Double-check if we're here because someone else is up */
- if (cpus_in_pm < num_online_cpus())
- ret = NOTIFY_OK;
- else
- /* We won't be called w/ CPU_PM_ENTER_FAILED */
- atomic_dec(&drv->cpus_in_pm);
- }
-
- return ret;
-}
-
-/**
- * rpmh_rsc_pd_callback() - Check if any of the AMCs are busy.
- * @nfb: Pointer to the genpd notifier block in struct rsc_drv.
- * @action: GENPD_NOTIFY_PRE_OFF, GENPD_NOTIFY_OFF, GENPD_NOTIFY_PRE_ON or GENPD_NOTIFY_ON.
- * @v: Unused
- *
- * This function is given to dev_pm_genpd_add_notifier() so we can be informed
- * about when cluster-pd is going down. When cluster go down we know no more active
- * transfers will be started so we write sleep/wake sets. This function gets
- * called from cpuidle code paths and also at system suspend time.
- *
- * If AMCs are not busy then writes cached sleep and wake messages to TCSes.
- * The firmware then takes care of triggering them when entering deepest low power modes.
- *
- * Return:
- * * NOTIFY_OK - success
- * * NOTIFY_BAD - failure
- */
-static int rpmh_rsc_pd_callback(struct notifier_block *nfb,
- unsigned long action, void *v)
-{
- struct rsc_drv *drv = container_of(nfb, struct rsc_drv, genpd_nb);
-
- /* We don't need to lock as genpd on/off are serialized */
- if ((action == GENPD_NOTIFY_PRE_OFF) &&
- (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client)))
- return NOTIFY_BAD;
-
- return NOTIFY_OK;
-}
-
-static int rpmh_rsc_pd_attach(struct rsc_drv *drv, struct device *dev)
-{
- int ret;
-
- pm_runtime_enable(dev);
- drv->genpd_nb.notifier_call = rpmh_rsc_pd_callback;
- ret = dev_pm_genpd_add_notifier(dev, &drv->genpd_nb);
- if (ret)
- pm_runtime_disable(dev);
-
- return ret;
-}
-
static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
{
struct tcs_type_config {
u32 type;
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 09/24] soc: qcom: rpmh-rsc: adjust headers for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (7 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 08/24] soc: qcom: rpmh-rsc: drop unused multi-threading and non-active TCS support Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 10/24] soc: qcom: rpmh-rsc: adjust probe " Caleb Connolly
` (15 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Remove unsupported / unused Linux headers and add those needed for
U-Boot.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh-rsc.c | 36 ++++++++++++------------------------
1 file changed, 12 insertions(+), 24 deletions(-)
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index fc8321bf208f..6b47c8001cac 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -5,39 +5,27 @@
*/
#define pr_fmt(fmt) "%s " fmt, KBUILD_MODNAME
-#include <linux/atomic.h>
-#include <linux/cpu_pm.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <dm/ofnode.h>
+#include <linux/bitmap.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 <linux/err.h>
+#include <linux/types.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <log.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
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 10/24] soc: qcom: rpmh-rsc: adjust probe for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (8 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 09/24] soc: qcom: rpmh-rsc: adjust headers for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 11/24] soc: qcom: rpmh-rsc: remaining U-Boot API changes Caleb Connolly
` (14 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Rework the rpmh-rsc initialization to use U-Boot's driver model and
initialize cmd-db.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh-internal.h | 14 ++---
drivers/soc/qcom/rpmh-rsc.c | 123 ++++++++++-----------------------------
2 files changed, 34 insertions(+), 103 deletions(-)
diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h
index 12c5b8d9cf86..ac8f6c35a7a4 100644
--- a/drivers/soc/qcom/rpmh-internal.h
+++ b/drivers/soc/qcom/rpmh-internal.h
@@ -7,17 +7,18 @@
#ifndef __RPM_INTERNAL_H__
#define __RPM_INTERNAL_H__
#include <linux/bitmap.h>
-#include <linux/wait.h>
#include <soc/qcom/tcs.h>
#define TCS_TYPE_NR 4
#define MAX_CMDS_PER_TCS 16
#define MAX_TCS_PER_TYPE 3
#define MAX_TCS_NR (MAX_TCS_PER_TYPE * TCS_TYPE_NR)
#define MAX_TCS_SLOTS (MAX_CMDS_PER_TCS * MAX_TCS_PER_TYPE)
+#define USEC_PER_SEC 1000000UL
+
struct rsc_drv;
/**
* struct tcs_group: group of Trigger Command Sets (TCS) to send state requests
@@ -63,10 +64,9 @@ struct tcs_group {
*/
struct rpmh_request {
struct tcs_request msg;
struct tcs_cmd cmd[MAX_RPMH_PAYLOAD];
- struct completion *completion;
- const struct device *dev;
+ const struct udevice *dev;
bool needs_free;
};
/**
@@ -78,9 +78,8 @@ struct rpmh_request {
* @batch_cache: Cache sleep and wake requests sent as batch
*/
struct rpmh_ctrlr {
struct list_head cache;
- spinlock_t cache_lock;
bool dirty;
struct list_head batch_cache;
};
@@ -122,17 +121,12 @@ struct rsc_drv {
void __iomem *base;
void __iomem *tcs_base;
int id;
int num_tcs;
- struct notifier_block rsc_pm;
- struct notifier_block genpd_nb;
- atomic_t cpus_in_pm;
struct tcs_group tcs[TCS_TYPE_NR];
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
- spinlock_t lock;
- wait_queue_head_t tcs_wait;
struct rpmh_ctrlr client;
- struct device *dev;
+ struct udevice *dev;
struct rsc_ver ver;
u32 *regs;
};
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 6b47c8001cac..2afe5005facf 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -385,20 +385,20 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
return 0;
}
-static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *drv)
+static int rpmh_probe_tcs_config(struct udevice *dev, struct rsc_drv *drv)
{
struct tcs_type_config {
u32 type;
u32 n;
} tcs_cfg[TCS_TYPE_NR] = { { 0 } };
- struct device_node *dn = pdev->dev.of_node;
+ ofnode dn = dev_ofnode(dev);
u32 config, max_tcs, ncpt, offset;
int i, ret, n, st = 0;
struct tcs_group *tcs;
- ret = of_property_read_u32(dn, "qcom,tcs-offset", &offset);
+ ret = ofnode_read_u32(dn, "qcom,tcs-offset", &offset);
if (ret)
return ret;
drv->tcs_base = drv->base + offset;
@@ -410,24 +410,15 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *d
ncpt = config & (DRV_NCPT_MASK << DRV_NCPT_SHIFT);
ncpt = ncpt >> DRV_NCPT_SHIFT;
- n = of_property_count_u32_elems(dn, "qcom,tcs-config");
- if (n != 2 * TCS_TYPE_NR)
- return -EINVAL;
+ n = ofnode_read_u32_array(dn, "qcom,tcs-config", (u32 *)tcs_cfg, 2 * TCS_TYPE_NR);
+ if (n < 0) {
+ log_err("RPMh: %s: error reading qcom,tcs-config %d\n", dev->name, n);
+ return n;
+ }
for (i = 0; i < TCS_TYPE_NR; i++) {
- ret = of_property_read_u32_index(dn, "qcom,tcs-config",
- i * 2, &tcs_cfg[i].type);
- if (ret)
- return ret;
- if (tcs_cfg[i].type >= TCS_TYPE_NR)
- return -EINVAL;
-
- ret = of_property_read_u32_index(dn, "qcom,tcs-config",
- i * 2 + 1, &tcs_cfg[i].n);
- if (ret)
- return ret;
if (tcs_cfg[i].n > MAX_TCS_PER_TYPE)
return -EINVAL;
}
@@ -456,43 +447,28 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, struct rsc_drv *d
return 0;
}
-static int rpmh_rsc_probe(struct platform_device *pdev)
+static int rpmh_rsc_probe(struct udevice *dev)
{
- struct device_node *dn = pdev->dev.of_node;
+ ofnode dn = dev_ofnode(dev);
struct rsc_drv *drv;
char drv_id[10] = {0};
- int ret, irq;
- u32 solver_config;
+ int ret;
u32 rsc_id;
- /*
- * Even though RPMh doesn't directly use cmd-db, all of its children
- * do. To avoid adding this check to our children we'll do it now.
- */
- ret = cmd_db_ready();
- if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Command DB not available (%d)\n",
- ret);
- return ret;
- }
+ drv = dev_get_priv(dev);
- drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL);
- if (!drv)
- return -ENOMEM;
-
- ret = of_property_read_u32(dn, "qcom,drv-id", &drv->id);
+ ret = ofnode_read_u32(dn, "qcom,drv-id", &drv->id);
if (ret)
return ret;
- drv->name = of_get_property(dn, "label", NULL);
+ drv->name = ofnode_get_property(dn, "label", NULL);
if (!drv->name)
- drv->name = dev_name(&pdev->dev);
+ drv->name = dev->name;
snprintf(drv_id, ARRAY_SIZE(drv_id), "drv-%d", drv->id);
- drv->base = devm_platform_ioremap_resource_byname(pdev, drv_id);
+ drv->base = (void __iomem *)dev_read_addr_name(dev, drv_id);
if (IS_ERR(drv->base))
return PTR_ERR(drv->base);
rsc_id = readl_relaxed(drv->base + RSC_DRV_ID);
@@ -505,84 +481,45 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->regs = rpmh_rsc_reg_offset_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offset_ver_2_7;
- ret = rpmh_probe_tcs_config(pdev, drv);
+ ret = rpmh_probe_tcs_config(dev, drv);
if (ret)
return ret;
spin_lock_init(&drv->lock);
init_waitqueue_head(&drv->tcs_wait);
bitmap_zero(drv->tcs_in_use, MAX_TCS_NR);
- irq = platform_get_irq(pdev, drv->id);
- if (irq < 0)
- return irq;
-
- ret = devm_request_irq(&pdev->dev, irq, tcs_tx_done,
- IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
- drv->name, drv);
- if (ret)
- return ret;
-
- /*
- * CPU PM/genpd notification are not required for controllers that support
- * 'HW solver' mode where they can be in autonomous mode executing low
- * power mode to power down.
- */
- solver_config = readl_relaxed(drv->base + drv->regs[DRV_SOLVER_CONFIG]);
- solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT;
- solver_config = solver_config >> DRV_HW_SOLVER_SHIFT;
- if (!solver_config) {
- if (pdev->dev.pm_domain) {
- ret = rpmh_rsc_pd_attach(drv, &pdev->dev);
- if (ret)
- return ret;
- } else {
- drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback;
- cpu_pm_register_notifier(&drv->rsc_pm);
- }
- }
-
/* Enable the active TCS to send requests immediately */
writel_relaxed(drv->tcs[ACTIVE_TCS].mask,
drv->tcs_base + drv->regs[RSC_DRV_IRQ_ENABLE]);
spin_lock_init(&drv->client.cache_lock);
INIT_LIST_HEAD(&drv->client.cache);
INIT_LIST_HEAD(&drv->client.batch_cache);
- dev_set_drvdata(&pdev->dev, drv);
- drv->dev = &pdev->dev;
+ dev_set_drvdata(dev, drv);
+ drv->dev = dev;
- ret = devm_of_platform_populate(&pdev->dev);
- if (ret && pdev->dev.pm_domain) {
- dev_pm_genpd_remove_notifier(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
- }
+ log_debug("RPMh: %s: v%d.%d\n", dev->name, drv->ver.major, drv->ver.minor);
return ret;
}
-static const struct of_device_id rpmh_drv_match[] = {
- { .compatible = "qcom,rpmh-rsc", },
+static const struct udevice_id qcom_rpmh_ids[] = {
+ { .compatible = "qcom,rpmh-rsc" },
{ }
};
-MODULE_DEVICE_TABLE(of, rpmh_drv_match);
-static struct platform_driver rpmh_driver = {
- .probe = rpmh_rsc_probe,
- .driver = {
- .name = "rpmh",
- .of_match_table = rpmh_drv_match,
- .suppress_bind_attrs = true,
- },
+U_BOOT_DRIVER(qcom_rpmh_rsc) = {
+ .name = "qcom_rpmh_rsc",
+ .id = UCLASS_MISC,
+ .priv_auto = sizeof(struct rsc_drv),
+ .probe = rpmh_rsc_probe,
+ .of_match = qcom_rpmh_ids,
+ /* rpmh is under CLUSTER_PD which we don't support, so skip trying to enable PDs */
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
};
-static int __init rpmh_driver_init(void)
-{
- return platform_driver_register(&rpmh_driver);
-}
-core_initcall(rpmh_driver_init);
-
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Driver");
MODULE_LICENSE("GPL v2");
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 11/24] soc: qcom: rpmh-rsc: remaining U-Boot API changes
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (9 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 10/24] soc: qcom: rpmh-rsc: adjust probe " Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 12/24] soc: qcom: rpmh: adjust headers for U-Boot Caleb Connolly
` (13 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Minor adjustments to fix building with U-Boot and work correctly as a
synchronous driver without interrupts. RPMh is fast enough that we can
get away with just firing off requests and assuming they complete.
U-Boot behaviour changes are annotated with a "U-Boot:" comment.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh-rsc.c | 78 +++++++++++++++++----------------------------
1 file changed, 29 insertions(+), 49 deletions(-)
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index 2afe5005facf..61fb2e695587 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -133,16 +133,8 @@ enum {
* | ...... |
* +---------------------------------------------------+
*/
-#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,
@@ -247,37 +239,18 @@ static void write_tcs_reg_sync(const struct rsc_drv *drv, int reg, int tcs_id,
*/
static struct tcs_group *get_tcs_for_msg(struct rsc_drv *drv,
const struct tcs_request *msg)
{
- int type;
- struct tcs_group *tcs;
-
- switch (msg->state) {
- case RPMH_ACTIVE_ONLY_STATE:
- type = ACTIVE_TCS;
- break;
- case RPMH_WAKE_ONLY_STATE:
- type = WAKE_TCS;
- break;
- case RPMH_SLEEP_STATE:
- type = SLEEP_TCS;
- break;
- default:
+ /*
+ * U-Boot: since we're single threaded and running synchronously we can
+ * just always used the first active TCS.
+ */
+ if (msg->state != RPMH_ACTIVE_ONLY_STATE) {
+ log_err("WARN: only ACTIVE_ONLY state supported\n");
return ERR_PTR(-EINVAL);
}
- /*
- * If we are making an active request on a RSC that does not have a
- * dedicated TCS for active state use, then re-purpose a wake TCS to
- * send active votes. This is safe because we ensure any active-only
- * transfers have finished before we use it (maybe by running from
- * the last CPU in PM code).
- */
- tcs = &drv->tcs[type];
- if (msg->state == RPMH_ACTIVE_ONLY_STATE && !tcs->num_tcs)
- tcs = &drv->tcs[WAKE_TCS];
-
- return tcs;
+ return &drv->tcs[ACTIVE_TCS];
}
/**
* __tcs_buffer_write() - Write to TCS hardware from a request; don't trigger.
@@ -297,11 +270,8 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
u32 cmd_enable = 0;
struct tcs_cmd *cmd;
int i, j;
- /* Convert all commands to RR when the request has wait_for_compl set */
- cmd_msgid |= msg->wait_for_compl ? CMD_MSGID_RESP_REQ : 0;
-
for (i = 0, j = cmd_id; i < msg->num_cmds; i++, j++) {
cmd = &msg->cmds[i];
cmd_enable |= BIT(j);
msgid = cmd_msgid;
@@ -313,9 +283,11 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_MSGID], tcs_id, j, msgid);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], tcs_id, j, cmd->addr);
write_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_DATA], tcs_id, j, cmd->data);
- trace_rpmh_send_msg(drv, tcs_id, msg->state, j, msgid, cmd);
+ debug("tcs(m): %d [%s] cmd(n): %d msgid: %#x addr: %#x data: %#x complete: %d\n",
+ tcs_id, msg->state == RPMH_ACTIVE_ONLY_STATE ? "active" : "?", j, msgid,
+ cmd->addr, cmd->data, cmd->wait);
}
cmd_enable |= read_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id);
write_tcs_reg(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, cmd_enable);
@@ -345,34 +317,28 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id,
*/
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
{
struct tcs_group *tcs;
- int tcs_id;
-
- might_sleep();
+ int tcs_id, i;
+ u32 addr;
tcs = get_tcs_for_msg(drv, msg);
if (IS_ERR(tcs))
return PTR_ERR(tcs);
- spin_lock_irq(&drv->lock);
-
- /* Wait forever for a free tcs. It better be there eventually! */
- wait_event_lock_irq(drv->tcs_wait,
- (tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0,
- drv->lock);
+ /* u-boot is single-threaded, always use the first TCS as we'll never conflict */
+ tcs_id = tcs->offset;
tcs->req[tcs_id - tcs->offset] = msg;
- set_bit(tcs_id, drv->tcs_in_use);
+ generic_set_bit(tcs_id, drv->tcs_in_use);
if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) {
/*
* Clear previously programmed WAKE commands in selected
* repurposed TCS to avoid triggering them. tcs->slots will be
* cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate()
*/
write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0);
}
- spin_unlock_irq(&drv->lock);
/*
* These two can be done after the lock is released because:
* - We marked "tcs_in_use" under lock.
@@ -382,8 +348,22 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg)
* of __tcs_set_trigger() below.
*/
__tcs_buffer_write(drv, tcs_id, 0, msg);
+ /* U-Boot: Now wait for the TCS to be cleared, indicating that we're done */
+ for (i = 0; i < USEC_PER_SEC; i++) {
+ addr = read_tcs_cmd(drv, drv->regs[RSC_DRV_CMD_ADDR], i, 0);
+ if (addr != msg->cmds[0].addr)
+ break;
+ udelay(1);
+ }
+
+ if (i == USEC_PER_SEC) {
+ log_err("%s: error writing %#x to %d:%#x\n", drv->name,
+ msg->cmds[0].addr, tcs_id, drv->regs[RSC_DRV_CMD_ADDR]);
+ return -EINVAL;
+ }
+
return 0;
}
static int rpmh_probe_tcs_config(struct udevice *dev, struct rsc_drv *drv)
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 12/24] soc: qcom: rpmh: adjust headers for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (10 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 11/24] soc: qcom: rpmh-rsc: remaining U-Boot API changes Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 13/24] soc: qcom: rpmh: drop unused functions Caleb Connolly
` (12 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Drop unused/unsupported Linux headers and add dm/device.h for U-Boot.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 8903ed956312..03ef4106c9a6 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -2,22 +2,14 @@
/*
* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
*/
-#include <linux/atomic.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
#include <linux/bug.h>
-#include <linux/interrupt.h>
-#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/lockdep.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
#include <linux/types.h>
-#include <linux/wait.h>
#include <soc/qcom/rpmh.h>
#include "rpmh-internal.h"
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 13/24] soc: qcom: rpmh: drop unused functions
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (11 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 12/24] soc: qcom: rpmh: adjust headers for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 14/24] soc: qcom: rpmh: U-Boot API changes Caleb Connolly
` (11 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
A lot of the features in here are only relevant when running
multi-threaded with interrupts. Drop everything except what we need to
run single-threaded with a single TCS (which is all the rpmh-rsc
framework in U-Boot supports).
Keep rpmh_write_async() for simplicity and make it wrap the regular
rpmh_write().
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh.c | 371 ------------------------------------------------
include/soc/qcom/rpmh.h | 25 +---
2 files changed, 3 insertions(+), 393 deletions(-)
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 03ef4106c9a6..22605e0291a1 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -31,124 +31,15 @@
}
#define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client)
-/**
- * struct cache_req: the request object for caching
- *
- * @addr: the address of the resource
- * @sleep_val: the sleep vote
- * @wake_val: the wake vote
- * @list: linked list obj
- */
-struct cache_req {
- u32 addr;
- u32 sleep_val;
- u32 wake_val;
- struct list_head list;
-};
-
-/**
- * struct batch_cache_req - An entry in our batch catch
- *
- * @list: linked list obj
- * @count: number of messages
- * @rpm_msgs: the messages
- */
-
-struct batch_cache_req {
- struct list_head list;
- int count;
- struct rpmh_request rpm_msgs[];
-};
-
static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
{
struct rsc_drv *drv = dev_get_drvdata(dev->parent);
return &drv->client;
}
-void rpmh_tx_done(const struct tcs_request *msg)
-{
- struct rpmh_request *rpm_msg = container_of(msg, struct rpmh_request,
- msg);
- struct completion *compl = rpm_msg->completion;
- bool free = rpm_msg->needs_free;
-
- if (!compl)
- goto exit;
-
- /* Signal the blocking thread we are done */
- complete(compl);
-
-exit:
- if (free)
- kfree(rpm_msg);
-}
-
-static struct cache_req *__find_req(struct rpmh_ctrlr *ctrlr, u32 addr)
-{
- struct cache_req *p, *req = NULL;
-
- list_for_each_entry(p, &ctrlr->cache, list) {
- if (p->addr == addr) {
- req = p;
- break;
- }
- }
-
- return req;
-}
-
-static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
- enum rpmh_state state,
- struct tcs_cmd *cmd)
-{
- struct cache_req *req;
- unsigned long flags;
- u32 old_sleep_val, old_wake_val;
-
- spin_lock_irqsave(&ctrlr->cache_lock, flags);
- req = __find_req(ctrlr, cmd->addr);
- if (req)
- goto existing;
-
- req = kzalloc(sizeof(*req), GFP_ATOMIC);
- if (!req) {
- req = ERR_PTR(-ENOMEM);
- goto unlock;
- }
-
- req->addr = cmd->addr;
- req->sleep_val = req->wake_val = UINT_MAX;
- list_add_tail(&req->list, &ctrlr->cache);
-
-existing:
- old_sleep_val = req->sleep_val;
- old_wake_val = req->wake_val;
-
- switch (state) {
- case RPMH_ACTIVE_ONLY_STATE:
- case RPMH_WAKE_ONLY_STATE:
- req->wake_val = cmd->data;
- break;
- case RPMH_SLEEP_STATE:
- req->sleep_val = cmd->data;
- break;
- }
-
- ctrlr->dirty |= (req->sleep_val != old_sleep_val ||
- req->wake_val != old_wake_val) &&
- req->sleep_val != UINT_MAX &&
- req->wake_val != UINT_MAX;
-
-unlock:
- spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
-
- return req;
-}
-
/**
* __rpmh_write: Cache and send the RPMH request
*
* @dev: The device making the request
@@ -199,40 +90,8 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
return 0;
}
-/**
- * rpmh_write_async: Write a set of RPMH commands
- *
- * @dev: The device making the request
- * @state: Active/sleep set
- * @cmd: The payload data
- * @n: The number of elements in payload
- *
- * Write a set of RPMH commands, the order of commands is maintained
- * and will be sent as a single shot.
- */
-int rpmh_write_async(const struct device *dev, enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 n)
-{
- struct rpmh_request *rpm_msg;
- int ret;
-
- rpm_msg = kzalloc(sizeof(*rpm_msg), GFP_ATOMIC);
- if (!rpm_msg)
- return -ENOMEM;
- rpm_msg->needs_free = true;
-
- ret = __fill_rpmh_msg(rpm_msg, state, cmd, n);
- if (ret) {
- kfree(rpm_msg);
- return ret;
- }
-
- return __rpmh_write(dev, state, rpm_msg);
-}
-EXPORT_SYMBOL_GPL(rpmh_write_async);
-
/**
* rpmh_write: Write a set of RPMH commands and block until response
*
* @dev: The device making the request
@@ -261,234 +120,4 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
WARN_ON(!ret);
return (ret > 0) ? 0 : -ETIMEDOUT;
}
EXPORT_SYMBOL_GPL(rpmh_write);
-
-static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ctrlr->cache_lock, flags);
- list_add_tail(&req->list, &ctrlr->batch_cache);
- ctrlr->dirty = true;
- spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
-}
-
-static int flush_batch(struct rpmh_ctrlr *ctrlr)
-{
- struct batch_cache_req *req;
- const struct rpmh_request *rpm_msg;
- int ret = 0;
- int i;
-
- /* Send Sleep/Wake requests to the controller, expect no response */
- list_for_each_entry(req, &ctrlr->batch_cache, list) {
- for (i = 0; i < req->count; i++) {
- rpm_msg = req->rpm_msgs + i;
- ret = rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr),
- &rpm_msg->msg);
- if (ret)
- break;
- }
- }
-
- return ret;
-}
-
-/**
- * rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
- * batch to finish.
- *
- * @dev: the device making the request
- * @state: Active/sleep set
- * @cmd: The payload data
- * @n: The array of count of elements in each batch, 0 terminated.
- *
- * Write a request to the RSC controller without caching. If the request
- * state is ACTIVE, then the requests are treated as completion request
- * and sent to the controller immediately. The function waits until all the
- * commands are complete. If the request was to SLEEP or WAKE_ONLY, then the
- * request is sent as fire-n-forget and no ack is expected.
- *
- * May sleep. Do not call from atomic contexts for ACTIVE_ONLY requests.
- */
-int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 *n)
-{
- struct batch_cache_req *req;
- struct rpmh_request *rpm_msgs;
- struct completion *compls;
- struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
- unsigned long time_left;
- int count = 0;
- int ret, i;
- void *ptr;
-
- if (!cmd || !n)
- return -EINVAL;
-
- while (n[count] > 0)
- count++;
- if (!count)
- return -EINVAL;
-
- ptr = kzalloc(sizeof(*req) +
- count * (sizeof(req->rpm_msgs[0]) + sizeof(*compls)),
- GFP_ATOMIC);
- if (!ptr)
- return -ENOMEM;
-
- req = ptr;
- compls = ptr + sizeof(*req) + count * sizeof(*rpm_msgs);
-
- req->count = count;
- rpm_msgs = req->rpm_msgs;
-
- for (i = 0; i < count; i++) {
- __fill_rpmh_msg(rpm_msgs + i, state, cmd, n[i]);
- cmd += n[i];
- }
-
- if (state != RPMH_ACTIVE_ONLY_STATE) {
- cache_batch(ctrlr, req);
- return 0;
- }
-
- for (i = 0; i < count; i++) {
- struct completion *compl = &compls[i];
-
- init_completion(compl);
- rpm_msgs[i].completion = compl;
- ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msgs[i].msg);
- if (ret) {
- pr_err("Error(%d) sending RPMH message addr=%#x\n",
- ret, rpm_msgs[i].msg.cmds[0].addr);
- break;
- }
- }
-
- time_left = RPMH_TIMEOUT_MS;
- while (i--) {
- time_left = wait_for_completion_timeout(&compls[i], time_left);
- if (!time_left) {
- /*
- * Better hope they never finish because they'll signal
- * the completion that we're going to free once
- * we've returned from this function.
- */
- WARN_ON(1);
- ret = -ETIMEDOUT;
- goto exit;
- }
- }
-
-exit:
- kfree(ptr);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(rpmh_write_batch);
-
-static int is_req_valid(struct cache_req *req)
-{
- return (req->sleep_val != UINT_MAX &&
- req->wake_val != UINT_MAX &&
- req->sleep_val != req->wake_val);
-}
-
-static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
- u32 addr, u32 data)
-{
- DEFINE_RPMH_MSG_ONSTACK(NULL, state, NULL, rpm_msg);
-
- /* Wake sets are always complete and sleep sets are not */
- rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE);
- rpm_msg.cmd[0].addr = addr;
- rpm_msg.cmd[0].data = data;
- rpm_msg.msg.num_cmds = 1;
-
- return rpmh_rsc_write_ctrl_data(ctrlr_to_drv(ctrlr), &rpm_msg.msg);
-}
-
-/**
- * rpmh_flush() - Flushes the buffered sleep and wake sets to TCSes
- *
- * @ctrlr: Controller making request to flush cached data
- *
- * Return:
- * * 0 - Success
- * * Error code - Otherwise
- */
-int rpmh_flush(struct rpmh_ctrlr *ctrlr)
-{
- struct cache_req *p;
- int ret = 0;
-
- lockdep_assert_irqs_disabled();
-
- /*
- * Currently rpmh_flush() is only called when we think we're running
- * on the last processor. If the lock is busy it means another
- * processor is up and it's better to abort than spin.
- */
- if (!spin_trylock(&ctrlr->cache_lock))
- return -EBUSY;
-
- if (!ctrlr->dirty) {
- pr_debug("Skipping flush, TCS has latest data.\n");
- goto write_next_wakeup;
- }
-
- /* Invalidate the TCSes first to avoid stale data */
- rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
-
- /* First flush the cached batch requests */
- ret = flush_batch(ctrlr);
- if (ret)
- goto exit;
-
- list_for_each_entry(p, &ctrlr->cache, list) {
- if (!is_req_valid(p)) {
- pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x",
- __func__, p->addr, p->sleep_val, p->wake_val);
- continue;
- }
- ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
- p->sleep_val);
- if (ret)
- goto exit;
- ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
- p->wake_val);
- if (ret)
- goto exit;
- }
-
- ctrlr->dirty = false;
-
-write_next_wakeup:
- rpmh_rsc_write_next_wakeup(ctrlr_to_drv(ctrlr));
-exit:
- spin_unlock(&ctrlr->cache_lock);
- return ret;
-}
-
-/**
- * rpmh_invalidate: Invalidate sleep and wake sets in batch_cache
- *
- * @dev: The device making the request
- *
- * Invalidate the sleep and wake values in batch_cache.
- */
-void rpmh_invalidate(const struct device *dev)
-{
- struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
- struct batch_cache_req *req, *tmp;
- unsigned long flags;
-
- spin_lock_irqsave(&ctrlr->cache_lock, flags);
- list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
- kfree(req);
- INIT_LIST_HEAD(&ctrlr->batch_cache);
- ctrlr->dirty = true;
- spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
-}
-EXPORT_SYMBOL_GPL(rpmh_invalidate);
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index bdbee1a97d36..9a5c5d992e04 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -13,35 +13,16 @@
#if IS_ENABLED(CONFIG_QCOM_RPMH)
int rpmh_write(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n);
-int rpmh_write_async(const struct device *dev, enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 n);
-
-int rpmh_write_batch(const struct device *dev, enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 *n);
-
-void rpmh_invalidate(const struct device *dev);
-
#else
static inline int rpmh_write(const struct device *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n)
{ return -ENODEV; }
-static inline int rpmh_write_async(const struct device *dev,
- enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 n)
-{ return -ENODEV; }
-
-static inline int rpmh_write_batch(const struct device *dev,
- enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 *n)
-{ return -ENODEV; }
-
-static inline void rpmh_invalidate(const struct device *dev)
-{
-}
-
#endif /* CONFIG_QCOM_RPMH */
+/* u-boot: no multithreading */
+#define rpmh_write_async(dev, state, cmd, n) rpmh_write(dev, state, cmd, n)
+
#endif /* __SOC_QCOM_RPMH_H__ */
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 14/24] soc: qcom: rpmh: U-Boot API changes
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (12 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 13/24] soc: qcom: rpmh: drop unused functions Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 15/24] soc: qcom: add build infrastructure Caleb Connolly
` (10 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Fix build errors, add some debug logging.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/qcom/rpmh.c | 53 +++++++++++++++++++------------------------------
include/soc/qcom/rpmh.h | 4 ++--
2 files changed, 22 insertions(+), 35 deletions(-)
diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c
index 22605e0291a1..96f14a9afdf2 100644
--- a/drivers/soc/qcom/rpmh.c
+++ b/drivers/soc/qcom/rpmh.c
@@ -15,27 +15,30 @@
#include "rpmh-internal.h"
#define RPMH_TIMEOUT_MS msecs_to_jiffies(10000)
-#define DEFINE_RPMH_MSG_ONSTACK(device, s, q, name) \
+#define DEFINE_RPMH_MSG_ONSTACK(device, s, name) \
struct rpmh_request name = { \
.msg = { \
.state = s, \
.cmds = name.cmd, \
.num_cmds = 0, \
- .wait_for_compl = true, \
}, \
.cmd = { { 0 } }, \
- .completion = q, \
.dev = device, \
- .needs_free = false, \
+ .needs_free = false, \
}
#define ctrlr_to_drv(ctrlr) container_of(ctrlr, struct rsc_drv, client)
-static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
+static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct udevice *dev)
{
- struct rsc_drv *drv = dev_get_drvdata(dev->parent);
+ struct rsc_drv *drv = (struct rsc_drv *)dev_get_priv(dev->parent);
+
+ if (!drv) {
+ log_err("BUG: no RPMh driver for %s (parent %s)\n", dev->name, dev->parent->name);
+ BUG();
+ }
return &drv->client;
}
@@ -49,36 +52,23 @@ static struct rpmh_ctrlr *get_rpmh_ctrlr(const struct device *dev)
* Cache the RPMH request and send if the state is ACTIVE_ONLY.
* SLEEP/WAKE_ONLY requests are not sent to the controller at
* this time. Use rpmh_flush() to send them to the controller.
*/
-static int __rpmh_write(const struct device *dev, enum rpmh_state state,
+static int __rpmh_write(const struct udevice *dev, enum rpmh_state state,
struct rpmh_request *rpm_msg)
{
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
- int ret = -EINVAL;
- struct cache_req *req;
- int i;
- /* Cache the request in our store and link the payload */
- for (i = 0; i < rpm_msg->msg.num_cmds; i++) {
- req = cache_rpm_request(ctrlr, state, &rpm_msg->msg.cmds[i]);
- if (IS_ERR(req))
- return PTR_ERR(req);
+ if (state != RPMH_ACTIVE_ONLY_STATE) {
+ log_err("only ACTIVE_ONLY state supported\n");
+ return -EINVAL;
}
- if (state == RPMH_ACTIVE_ONLY_STATE) {
- ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
- } else {
- /* Clean up our call by spoofing tx_done */
- ret = 0;
- rpmh_tx_done(&rpm_msg->msg);
- }
-
- return ret;
+ return rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg);
}
static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
- const struct tcs_cmd *cmd, u32 n)
+ const struct tcs_cmd *cmd, u32 n)
{
if (!cmd || !n || n > MAX_RPMH_PAYLOAD)
return -EINVAL;
@@ -87,8 +77,10 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
req->msg.state = state;
req->msg.cmds = req->cmd;
req->msg.num_cmds = n;
+ debug("rpmh_msg: %d, %d cmds [first %#x/%#x]\n", state, n, cmd->addr, cmd->data);
+
return 0;
}
/**
@@ -100,24 +92,19 @@ static int __fill_rpmh_msg(struct rpmh_request *req, enum rpmh_state state,
* @n: The number of elements in @cmd
*
* May sleep. Do not call from atomic contexts.
*/
-int rpmh_write(const struct device *dev, enum rpmh_state state,
+int rpmh_write(const struct udevice *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n)
{
- DECLARE_COMPLETION_ONSTACK(compl);
- DEFINE_RPMH_MSG_ONSTACK(dev, state, &compl, rpm_msg);
+ DEFINE_RPMH_MSG_ONSTACK(dev, state, rpm_msg);
int ret;
ret = __fill_rpmh_msg(&rpm_msg, state, cmd, n);
if (ret)
return ret;
ret = __rpmh_write(dev, state, &rpm_msg);
- if (ret)
- return ret;
- ret = wait_for_completion_timeout(&compl, RPMH_TIMEOUT_MS);
- WARN_ON(!ret);
- return (ret > 0) ? 0 : -ETIMEDOUT;
+ return ret;
}
EXPORT_SYMBOL_GPL(rpmh_write);
diff --git a/include/soc/qcom/rpmh.h b/include/soc/qcom/rpmh.h
index 9a5c5d992e04..3421fbf1ee3e 100644
--- a/include/soc/qcom/rpmh.h
+++ b/include/soc/qcom/rpmh.h
@@ -5,14 +5,14 @@
#ifndef __SOC_QCOM_RPMH_H__
#define __SOC_QCOM_RPMH_H__
+#include <dm/device-internal.h>
#include <soc/qcom/tcs.h>
-#include <linux/platform_device.h>
#if IS_ENABLED(CONFIG_QCOM_RPMH)
-int rpmh_write(const struct device *dev, enum rpmh_state state,
+int rpmh_write(const struct udevice *dev, enum rpmh_state state,
const struct tcs_cmd *cmd, u32 n);
#else
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 15/24] soc: qcom: add build infrastructure
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (13 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 14/24] soc: qcom: rpmh: U-Boot API changes Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 12:29 ` Neil Armstrong
2024-07-15 10:08 ` [PATCH v6 16/24] power: regulator: import qcom-rpmh-regulator from Linux Caleb Connolly
` (9 subsequent siblings)
24 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Add Kconfig / Makefiles to build rpmh and cmd-db drivers.
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/soc/Kconfig | 1 +
drivers/soc/Makefile | 1 +
drivers/soc/qcom/Kconfig | 27 +++++++++++++++++++++++++++
drivers/soc/qcom/Makefile | 4 ++++
4 files changed, 33 insertions(+)
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index cee506fe4747..8ef408d9ba1b 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -47,8 +47,9 @@ config SOC_XILINX_VERSAL_NET
Enable this option to select SoC device id driver for Xilinx Versal NET.
This allows other drivers to verify the SoC familiy & revision using
matching SoC attributes.
+source "drivers/soc/qcom/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/ti/Kconfig"
endmenu
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 5ec89a053165..00e6a5ac8e2b 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -2,8 +2,9 @@
#
# Makefile for the U-Boot SOC specific device drivers.
obj-$(CONFIG_SOC_AMD_VERSAL2) += soc_amd_versal2.o
+obj-$(CONFIG_SOC_QCOM) += qcom/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-$(CONFIG_SOC_TI) += ti/
obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o
obj-$(CONFIG_SOC_DEVICE_TI_K3) += soc_ti_k3.o
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
new file mode 100644
index 000000000000..4aa7833930c7
--- /dev/null
+++ b/drivers/soc/qcom/Kconfig
@@ -0,0 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# QCOM Soc drivers
+#
+menuconfig SOC_QCOM
+ bool "Qualcomm SOC drivers support"
+ help
+ Say Y here if you want to enable Qualcomm SOC drivers support.
+
+if SOC_QCOM
+
+config QCOM_COMMAND_DB
+ bool "Qualcomm Command DB"
+ help
+ Command DB queries shared memory by key string for shared system
+ resources. Platform drivers that require to set state of a shared
+ resource on a RPM-hardened platform must use this database to get
+ SoC specific identifier and information for the shared resources.
+
+config QCOM_RPMH
+ bool "Qualcomm RPMh support"
+ depends on QCOM_COMMAND_DB
+ help
+ Say y here to support the Qualcomm RPMh (resource peripheral manager)
+ if you need to control regulators on Qualcomm platforms, say y here.
+
+endif # SOC_QCOM
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
new file mode 100644
index 000000000000..78fae8bbfa16
--- /dev/null
+++ b/drivers/soc/qcom/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
+obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o rpmh.o
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v6 15/24] soc: qcom: add build infrastructure
2024-07-15 10:08 ` [PATCH v6 15/24] soc: qcom: add build infrastructure Caleb Connolly
@ 2024-07-15 12:29 ` Neil Armstrong
0 siblings, 0 replies; 36+ messages in thread
From: Neil Armstrong @ 2024-07-15 12:29 UTC (permalink / raw)
To: Caleb Connolly, Tom Rini, Sumit Garg, Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
On 15/07/2024 12:08, Caleb Connolly wrote:
> Add Kconfig / Makefiles to build rpmh and cmd-db drivers.
>
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
> drivers/soc/Kconfig | 1 +
> drivers/soc/Makefile | 1 +
> drivers/soc/qcom/Kconfig | 27 +++++++++++++++++++++++++++
> drivers/soc/qcom/Makefile | 4 ++++
> 4 files changed, 33 insertions(+)
>
> diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
> index cee506fe4747..8ef408d9ba1b 100644
> --- a/drivers/soc/Kconfig
> +++ b/drivers/soc/Kconfig
> @@ -47,8 +47,9 @@ config SOC_XILINX_VERSAL_NET
> Enable this option to select SoC device id driver for Xilinx Versal NET.
> This allows other drivers to verify the SoC familiy & revision using
> matching SoC attributes.
>
> +source "drivers/soc/qcom/Kconfig"
> source "drivers/soc/samsung/Kconfig"
> source "drivers/soc/ti/Kconfig"
>
> endmenu
> diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
> index 5ec89a053165..00e6a5ac8e2b 100644
> --- a/drivers/soc/Makefile
> +++ b/drivers/soc/Makefile
> @@ -2,8 +2,9 @@
> #
> # Makefile for the U-Boot SOC specific device drivers.
>
> obj-$(CONFIG_SOC_AMD_VERSAL2) += soc_amd_versal2.o
> +obj-$(CONFIG_SOC_QCOM) += qcom/
> obj-$(CONFIG_SOC_SAMSUNG) += samsung/
> obj-$(CONFIG_SOC_TI) += ti/
> obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o
> obj-$(CONFIG_SOC_DEVICE_TI_K3) += soc_ti_k3.o
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
> new file mode 100644
> index 000000000000..4aa7833930c7
> --- /dev/null
> +++ b/drivers/soc/qcom/Kconfig
> @@ -0,0 +1,27 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +#
> +# QCOM Soc drivers
> +#
> +menuconfig SOC_QCOM
> + bool "Qualcomm SOC drivers support"
> + help
> + Say Y here if you want to enable Qualcomm SOC drivers support.
> +
> +if SOC_QCOM
> +
> +config QCOM_COMMAND_DB
> + bool "Qualcomm Command DB"
> + help
> + Command DB queries shared memory by key string for shared system
> + resources. Platform drivers that require to set state of a shared
> + resource on a RPM-hardened platform must use this database to get
> + SoC specific identifier and information for the shared resources.
> +
> +config QCOM_RPMH
> + bool "Qualcomm RPMh support"
> + depends on QCOM_COMMAND_DB
> + help
> + Say y here to support the Qualcomm RPMh (resource peripheral manager)
> + if you need to control regulators on Qualcomm platforms, say y here.
> +
> +endif # SOC_QCOM
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
> new file mode 100644
> index 000000000000..78fae8bbfa16
> --- /dev/null
> +++ b/drivers/soc/qcom/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +
> +obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
> +obj-$(CONFIG_QCOM_RPMH) += rpmh-rsc.o rpmh.o
>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v6 16/24] power: regulator: import qcom-rpmh-regulator from Linux
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (14 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 15/24] soc: qcom: add build infrastructure Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 17/24] power: regulator: qcom-rpmh-regulator: adjust headers for U-Boot Caleb Connolly
` (8 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Import the driver from Linux 6.10-rc6.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 1709 +++++++++++++++++++++++++
1 file changed, 1709 insertions(+)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
new file mode 100644
index 000000000000..80e304711345
--- /dev/null
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -0,0 +1,1709 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2018-2021, The Linux Foundation. All rights reserved.
+// Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
+
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+
+#include <soc/qcom/cmd-db.h>
+#include <soc/qcom/rpmh.h>
+
+#include <dt-bindings/regulator/qcom,rpmh-regulator.h>
+
+/**
+ * enum rpmh_regulator_type - supported RPMh accelerator types
+ * @VRM: RPMh VRM accelerator which supports voting on enable, voltage,
+ * and mode of LDO, SMPS, and BOB type PMIC regulators.
+ * @XOB: RPMh XOB accelerator which supports voting on the enable state
+ * of PMIC regulators.
+ */
+enum rpmh_regulator_type {
+ VRM,
+ XOB,
+};
+
+#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
+#define RPMH_REGULATOR_REG_ENABLE 0x4
+#define RPMH_REGULATOR_REG_VRM_MODE 0x8
+
+#define PMIC4_LDO_MODE_RETENTION 4
+#define PMIC4_LDO_MODE_LPM 5
+#define PMIC4_LDO_MODE_HPM 7
+
+#define PMIC4_SMPS_MODE_RETENTION 4
+#define PMIC4_SMPS_MODE_PFM 5
+#define PMIC4_SMPS_MODE_AUTO 6
+#define PMIC4_SMPS_MODE_PWM 7
+
+#define PMIC4_BOB_MODE_PASS 0
+#define PMIC4_BOB_MODE_PFM 1
+#define PMIC4_BOB_MODE_AUTO 2
+#define PMIC4_BOB_MODE_PWM 3
+
+#define PMIC5_LDO_MODE_RETENTION 3
+#define PMIC5_LDO_MODE_LPM 4
+#define PMIC5_LDO_MODE_HPM 7
+
+#define PMIC5_SMPS_MODE_RETENTION 3
+#define PMIC5_SMPS_MODE_PFM 4
+#define PMIC5_SMPS_MODE_AUTO 6
+#define PMIC5_SMPS_MODE_PWM 7
+
+#define PMIC5_BOB_MODE_PASS 2
+#define PMIC5_BOB_MODE_PFM 4
+#define PMIC5_BOB_MODE_AUTO 6
+#define PMIC5_BOB_MODE_PWM 7
+
+/**
+ * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
+ * @regulator_type: RPMh accelerator type used to manage this
+ * regulator
+ * @ops: Pointer to regulator ops callback structure
+ * @voltage_ranges: The possible ranges of voltages supported by this
+ * PMIC regulator type
+ * @n_linear_ranges: Number of entries in voltage_ranges
+ * @n_voltages: The number of unique voltage set points defined
+ * by voltage_ranges
+ * @hpm_min_load_uA: Minimum load current in microamps that requires
+ * high power mode (HPM) operation. This is used
+ * for LDO hardware type regulators only.
+ * @pmic_mode_map: Array indexed by regulator framework mode
+ * containing PMIC hardware modes. Must be large
+ * enough to index all framework modes supported
+ * by this regulator hardware type.
+ * @of_map_mode: Maps an RPMH_REGULATOR_MODE_* mode value defined
+ * in device tree to a regulator framework mode
+ */
+struct rpmh_vreg_hw_data {
+ enum rpmh_regulator_type regulator_type;
+ const struct regulator_ops *ops;
+ const struct linear_range *voltage_ranges;
+ int n_linear_ranges;
+ int n_voltages;
+ int hpm_min_load_uA;
+ const int *pmic_mode_map;
+ unsigned int (*of_map_mode)(unsigned int mode);
+};
+
+/**
+ * struct rpmh_vreg - individual RPMh regulator data structure encapsulating a
+ * single regulator device
+ * @dev: Device pointer for the top-level PMIC RPMh
+ * regulator parent device. This is used as a
+ * handle in RPMh write requests.
+ * @addr: Base address of the regulator resource within
+ * an RPMh accelerator
+ * @rdesc: Regulator descriptor
+ * @hw_data: PMIC regulator configuration data for this RPMh
+ * regulator
+ * @always_wait_for_ack: Boolean flag indicating if a request must always
+ * wait for an ACK from RPMh before continuing even
+ * if it corresponds to a strictly lower power
+ * state (e.g. enabled --> disabled).
+ * @enabled: Flag indicating if the regulator is enabled or
+ * not
+ * @bypassed: Boolean indicating if the regulator is in
+ * bypass (pass-through) mode or not. This is
+ * only used by BOB rpmh-regulator resources.
+ * @voltage_selector: Selector used for get_voltage_sel() and
+ * set_voltage_sel() callbacks
+ * @mode: RPMh VRM regulator current framework mode
+ */
+struct rpmh_vreg {
+ struct device *dev;
+ u32 addr;
+ struct regulator_desc rdesc;
+ const struct rpmh_vreg_hw_data *hw_data;
+ bool always_wait_for_ack;
+
+ int enabled;
+ bool bypassed;
+ int voltage_selector;
+ unsigned int mode;
+};
+
+/**
+ * struct rpmh_vreg_init_data - initialization data for an RPMh regulator
+ * @name: Name for the regulator which also corresponds
+ * to the device tree subnode name of the regulator
+ * @resource_name: RPMh regulator resource name format string.
+ * This must include exactly one field: '%s' which
+ * is filled at run-time with the PMIC ID provided
+ * by device tree property qcom,pmic-id. Example:
+ * "ldo%s1" for RPMh resource "ldoa1".
+ * @supply_name: Parent supply regulator name
+ * @hw_data: Configuration data for this PMIC regulator type
+ */
+struct rpmh_vreg_init_data {
+ const char *name;
+ const char *resource_name;
+ const char *supply_name;
+ const struct rpmh_vreg_hw_data *hw_data;
+};
+
+/**
+ * rpmh_regulator_send_request() - send the request to RPMh
+ * @vreg: Pointer to the RPMh regulator
+ * @cmd: Pointer to the RPMh command to send
+ * @wait_for_ack: Boolean indicating if execution must wait until the
+ * request has been acknowledged as complete
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_send_request(struct rpmh_vreg *vreg,
+ struct tcs_cmd *cmd, bool wait_for_ack)
+{
+ int ret;
+
+ if (wait_for_ack || vreg->always_wait_for_ack)
+ ret = rpmh_write(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
+ else
+ ret = rpmh_write_async(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd,
+ 1);
+
+ return ret;
+}
+
+static int _rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector, bool wait_for_ack)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE,
+ };
+ int ret;
+
+ /* VRM voltage control register is set with voltage in millivolts. */
+ cmd.data = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev,
+ selector), 1000);
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack);
+ if (!ret)
+ vreg->voltage_selector = selector;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (vreg->enabled == -EINVAL) {
+ /*
+ * Cache the voltage and send it later when the regulator is
+ * enabled or disabled.
+ */
+ vreg->voltage_selector = selector;
+ return 0;
+ }
+
+ return _rpmh_regulator_vrm_set_voltage_sel(rdev, selector,
+ selector > vreg->voltage_selector);
+}
+
+static int rpmh_regulator_vrm_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->voltage_selector;
+}
+
+static int rpmh_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->enabled;
+}
+
+static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
+ .data = enable,
+ };
+ int ret;
+
+ if (vreg->enabled == -EINVAL &&
+ vreg->voltage_selector != -ENOTRECOVERABLE) {
+ ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
+ vreg->voltage_selector, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = rpmh_regulator_send_request(vreg, &cmd, enable);
+ if (!ret)
+ vreg->enabled = enable;
+
+ return ret;
+}
+
+static int rpmh_regulator_enable(struct regulator_dev *rdev)
+{
+ return rpmh_regulator_set_enable_state(rdev, true);
+}
+
+static int rpmh_regulator_disable(struct regulator_dev *rdev)
+{
+ return rpmh_regulator_set_enable_state(rdev, false);
+}
+
+static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,
+ unsigned int mode, bool bypassed)
+{
+ struct tcs_cmd cmd = {
+ .addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE,
+ };
+ int pmic_mode;
+
+ if (mode > REGULATOR_MODE_STANDBY)
+ return -EINVAL;
+
+ pmic_mode = vreg->hw_data->pmic_mode_map[mode];
+ if (pmic_mode < 0)
+ return pmic_mode;
+
+ if (bypassed)
+ cmd.data = PMIC4_BOB_MODE_PASS;
+ else
+ cmd.data = pmic_mode;
+
+ return rpmh_regulator_send_request(vreg, &cmd, true);
+}
+
+static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (mode == vreg->mode)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed);
+ if (!ret)
+ vreg->mode = mode;
+
+ return ret;
+}
+
+static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return vreg->mode;
+}
+
+/**
+ * rpmh_regulator_vrm_get_optimum_mode() - get the mode based on the load
+ * @rdev: Regulator device pointer for the rpmh-regulator
+ * @input_uV: Input voltage
+ * @output_uV: Output voltage
+ * @load_uA: Aggregated load current in microamps
+ *
+ * This function is used in the regulator_ops for VRM type RPMh regulator
+ * devices.
+ *
+ * Return: 0 on success, errno on failure
+ */
+static unsigned int rpmh_regulator_vrm_get_optimum_mode(
+ struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (load_uA >= vreg->hw_data->hpm_min_load_uA)
+ return REGULATOR_MODE_NORMAL;
+ else
+ return REGULATOR_MODE_IDLE;
+}
+
+static int rpmh_regulator_vrm_set_bypass(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ int ret;
+
+ if (vreg->bypassed == enable)
+ return 0;
+
+ ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, enable);
+ if (!ret)
+ vreg->bypassed = enable;
+
+ return ret;
+}
+
+static int rpmh_regulator_vrm_get_bypass(struct regulator_dev *rdev,
+ bool *enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ *enable = vreg->bypassed;
+
+ return 0;
+}
+
+static const struct regulator_ops rpmh_regulator_vrm_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .get_optimum_mode = rpmh_regulator_vrm_get_optimum_mode,
+};
+
+static const struct regulator_ops rpmh_regulator_vrm_bypass_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+ .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
+ .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
+ .list_voltage = regulator_list_voltage_linear_range,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+ .set_bypass = rpmh_regulator_vrm_set_bypass,
+ .get_bypass = rpmh_regulator_vrm_get_bypass,
+};
+
+static const struct regulator_ops rpmh_regulator_xob_ops = {
+ .enable = rpmh_regulator_enable,
+ .disable = rpmh_regulator_disable,
+ .is_enabled = rpmh_regulator_is_enabled,
+};
+
+/**
+ * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
+ * @vreg: Pointer to the individual rpmh-regulator resource
+ * @dev: Pointer to the top level rpmh-regulator PMIC device
+ * @node: Pointer to the individual rpmh-regulator resource
+ * device node
+ * @pmic_id: String used to identify the top level rpmh-regulator
+ * PMIC device on the board
+ * @pmic_rpmh_data: Pointer to a null-terminated array of rpmh-regulator
+ * resources defined for the top level PMIC device
+ *
+ * Return: 0 on success, errno on failure
+ */
+static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
+ struct device_node *node, const char *pmic_id,
+ const struct rpmh_vreg_init_data *pmic_rpmh_data)
+{
+ struct regulator_config reg_config = {};
+ char rpmh_resource_name[20] = "";
+ const struct rpmh_vreg_init_data *rpmh_data;
+ struct regulator_init_data *init_data;
+ struct regulator_dev *rdev;
+ int ret;
+
+ vreg->dev = dev;
+
+ for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
+ if (of_node_name_eq(node, rpmh_data->name))
+ break;
+
+ if (!rpmh_data->name) {
+ dev_err(dev, "Unknown regulator %pOFn\n", node);
+ return -EINVAL;
+ }
+
+ scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
+ rpmh_data->resource_name, pmic_id);
+
+ vreg->addr = cmd_db_read_addr(rpmh_resource_name);
+ if (!vreg->addr) {
+ dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
+ node, rpmh_resource_name);
+ return -ENODEV;
+ }
+
+ vreg->rdesc.name = rpmh_data->name;
+ vreg->rdesc.supply_name = rpmh_data->supply_name;
+ vreg->hw_data = rpmh_data->hw_data;
+
+ vreg->enabled = -EINVAL;
+ vreg->voltage_selector = -ENOTRECOVERABLE;
+ vreg->mode = REGULATOR_MODE_INVALID;
+
+ if (rpmh_data->hw_data->n_voltages) {
+ vreg->rdesc.linear_ranges = rpmh_data->hw_data->voltage_ranges;
+ vreg->rdesc.n_linear_ranges = rpmh_data->hw_data->n_linear_ranges;
+ vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages;
+ }
+
+ vreg->always_wait_for_ack = of_property_read_bool(node,
+ "qcom,always-wait-for-ack");
+
+ vreg->rdesc.owner = THIS_MODULE;
+ vreg->rdesc.type = REGULATOR_VOLTAGE;
+ vreg->rdesc.ops = vreg->hw_data->ops;
+ vreg->rdesc.of_map_mode = vreg->hw_data->of_map_mode;
+
+ init_data = of_get_regulator_init_data(dev, node, &vreg->rdesc);
+ if (!init_data)
+ return -ENOMEM;
+
+ if (rpmh_data->hw_data->regulator_type == XOB &&
+ init_data->constraints.min_uV &&
+ init_data->constraints.min_uV == init_data->constraints.max_uV) {
+ vreg->rdesc.fixed_uV = init_data->constraints.min_uV;
+ vreg->rdesc.n_voltages = 1;
+ }
+
+ reg_config.dev = dev;
+ reg_config.init_data = init_data;
+ reg_config.of_node = node;
+ reg_config.driver_data = vreg;
+
+ rdev = devm_regulator_register(dev, &vreg->rdesc, ®_config);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
+ node, ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
+ node, rpmh_resource_name, vreg->addr);
+
+ return 0;
+}
+
+static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_LDO_MODE_LPM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_LDO_MODE_HPM,
+ [REGULATOR_MODE_FAST] = -EINVAL,
+};
+
+static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC5_LDO_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC5_LDO_MODE_LPM,
+ [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM,
+ [REGULATOR_MODE_FAST] = -EINVAL,
+};
+
+static const int pmic_mode_map_pmic5_ldo_hpm[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = -EINVAL,
+ [REGULATOR_MODE_IDLE] = -EINVAL,
+ [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM,
+ [REGULATOR_MODE_FAST] = -EINVAL,
+};
+
+static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
+{
+ unsigned int mode;
+
+ switch (rpmh_mode) {
+ case RPMH_REGULATOR_MODE_HPM:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case RPMH_REGULATOR_MODE_LPM:
+ mode = REGULATOR_MODE_IDLE;
+ break;
+ case RPMH_REGULATOR_MODE_RET:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ default:
+ mode = REGULATOR_MODE_INVALID;
+ break;
+ }
+
+ return mode;
+}
+
+static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC4_SMPS_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_SMPS_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM,
+};
+
+static const int pmic_mode_map_pmic5_smps[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = PMIC5_SMPS_MODE_RETENTION,
+ [REGULATOR_MODE_IDLE] = PMIC5_SMPS_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC5_SMPS_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC5_SMPS_MODE_PWM,
+};
+
+static unsigned int
+rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
+{
+ unsigned int mode;
+
+ switch (rpmh_mode) {
+ case RPMH_REGULATOR_MODE_HPM:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case RPMH_REGULATOR_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case RPMH_REGULATOR_MODE_LPM:
+ mode = REGULATOR_MODE_IDLE;
+ break;
+ case RPMH_REGULATOR_MODE_RET:
+ mode = REGULATOR_MODE_STANDBY;
+ break;
+ default:
+ mode = REGULATOR_MODE_INVALID;
+ break;
+ }
+
+ return mode;
+}
+
+static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = -EINVAL,
+ [REGULATOR_MODE_IDLE] = PMIC4_BOB_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC4_BOB_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM,
+};
+
+static const int pmic_mode_map_pmic5_bob[REGULATOR_MODE_STANDBY + 1] = {
+ [REGULATOR_MODE_INVALID] = -EINVAL,
+ [REGULATOR_MODE_STANDBY] = -EINVAL,
+ [REGULATOR_MODE_IDLE] = PMIC5_BOB_MODE_PFM,
+ [REGULATOR_MODE_NORMAL] = PMIC5_BOB_MODE_AUTO,
+ [REGULATOR_MODE_FAST] = PMIC5_BOB_MODE_PWM,
+};
+
+static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
+{
+ unsigned int mode;
+
+ switch (rpmh_mode) {
+ case RPMH_REGULATOR_MODE_HPM:
+ mode = REGULATOR_MODE_FAST;
+ break;
+ case RPMH_REGULATOR_MODE_AUTO:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ case RPMH_REGULATOR_MODE_LPM:
+ mode = REGULATOR_MODE_IDLE;
+ break;
+ default:
+ mode = REGULATOR_MODE_INVALID;
+ break;
+ }
+
+ return mode;
+}
+
+static const struct rpmh_vreg_hw_data pmic4_pldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_pldo_lv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_nldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic4_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 216,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 259,
+ .pmic_mode_map = pmic_mode_map_pmic4_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_bob = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_bypass_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 84,
+ .pmic_mode_map = pmic_mode_map_pmic4_bob,
+ .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic4_lvs = {
+ .regulator_type = XOB,
+ .ops = &rpmh_regulator_xob_ops,
+ /* LVS hardware does not support voltage or mode configuration. */
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 63,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 188,
+ .hpm_min_load_uA = 10000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo502 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 256,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_pldo502ln = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 2, 200000),
+ REGULATOR_LINEAR_RANGE(2608000, 3, 28, 16000),
+ REGULATOR_LINEAR_RANGE(3104000, 29, 30, 96000),
+ REGULATOR_LINEAR_RANGE(3312000, 31, 31, 0),
+ },
+ .n_linear_ranges = 4,
+ .n_voltages = 32,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_nldo = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 124,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 211,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_nldo502 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_drms_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(528000, 0, 127, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 128,
+ .hpm_min_load_uA = 30000,
+ .pmic_mode_map = pmic_mode_map_pmic5_ldo,
+ .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 216,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 264,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 264,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 268,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 268,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 215,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 236,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_hfsmps515_1 = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(900000, 0, 4, 16000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 5,
+ .pmic_mode_map = pmic_mode_map_pmic5_smps,
+ .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
+};
+
+static const struct rpmh_vreg_hw_data pmic5_bob = {
+ .regulator_type = VRM,
+ .ops = &rpmh_regulator_vrm_bypass_ops,
+ .voltage_ranges = (struct linear_range[]) {
+ REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000),
+ },
+ .n_linear_ranges = 1,
+ .n_voltages = 32,
+ .pmic_mode_map = pmic_mode_map_pmic5_bob,
+ .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
+};
+
+#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
+{ \
+ .name = _name, \
+ .resource_name = _resource_name, \
+ .hw_data = _hw_data, \
+ .supply_name = _supply_name, \
+}
+
+static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"),
+ RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"),
+ RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"),
+ RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"),
+ RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"),
+ RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"),
+ RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"),
+ RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"),
+ RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"),
+ RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
+ RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
+ RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
+ RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_hfsmps510, "vdd-s10"),
+ RPMH_VREG("smps11", "smp%s11", &pmic5_hfsmps510, "vdd-s11"),
+ RPMH_VREG("smps12", "smp%s12", &pmic5_hfsmps510, "vdd-s12"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l5"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l12"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo_lv, "vdd-l2-l8"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l2-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l6-l9-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
+ RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8450_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"),
+ RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"),
+ RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515_1, "vdd-s2"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm8010_vreg_data[] = {
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo502, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo502, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo502ln, "vdd-l3-l4"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo502ln, "vdd-l3-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo502, "vdd-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo502ln, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo502, "vdd-l7"),
+};
+
+static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l4-l7-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
+ RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm6350_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, NULL),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, NULL),
+ /* smps3 - smps5 not configured */
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, NULL),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, NULL),
+ /* ldo17 not configured */
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, NULL),
+ RPMH_VREG("ldo22", "ldo%s22", &pmic5_nldo, NULL),
+};
+
+static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l9"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l12"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l7-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l3-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l4-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l10-l11-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmx65_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l18"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l6-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo, "vdd-l17"),
+ /* ldo18 not configured */
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, "vdd-l19"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, "vdd-l20"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, "vdd-l21"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmx75_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
+ RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"),
+ RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo_lv, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l8-l9"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo515, "vdd-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo515, "vdd-l4-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo515, "vdd-l17"),
+ /* ldo18 not configured */
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo515, "vdd-l19"),
+ RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo515, "vdd-l20-l21"),
+ RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo515, "vdd-l20-l21"),
+};
+
+static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
+ RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"),
+ RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps515, "vdd-s3"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm660_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
+ RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
+ RPMH_VREG("smps6", "smp%s6", &pmic4_hfsmps3, "vdd-s6"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l3"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l2-l3"),
+ /* ldo4 is inaccessible on PM660 */
+ RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l5"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic4_nldo, "vdd-l1-l6-l7"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo11", "ldo%s11", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
+ RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo17", "ldo%s17", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
+ {}
+};
+
+static const struct rpmh_vreg_init_data pm660l_vreg_data[] = {
+ RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
+ RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
+ RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3-s4"),
+ RPMH_VREG("smps5", "smp%s5", &pmic4_ftsmps426, "vdd-s5"),
+ RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l9-l10"),
+ RPMH_VREG("ldo2", "ldo%s2", &pmic4_pldo, "vdd-l2"),
+ RPMH_VREG("ldo3", "ldo%s3", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo4", "ldo%s4", &pmic4_pldo, "vdd-l4-l6"),
+ RPMH_VREG("ldo5", "ldo%s5", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l4-l6"),
+ RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
+ RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
+ {}
+};
+
+static int rpmh_regulator_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct rpmh_vreg_init_data *vreg_data;
+ struct device_node *node;
+ struct rpmh_vreg *vreg;
+ const char *pmic_id;
+ int ret;
+
+ vreg_data = of_device_get_match_data(dev);
+ if (!vreg_data)
+ return -ENODEV;
+
+ ret = of_property_read_string(dev->of_node, "qcom,pmic-id", &pmic_id);
+ if (ret < 0) {
+ dev_err(dev, "qcom,pmic-id missing in DT node\n");
+ return ret;
+ }
+
+ for_each_available_child_of_node(dev->of_node, node) {
+ vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
+ if (!vreg) {
+ of_node_put(node);
+ return -ENOMEM;
+ }
+
+ ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id,
+ vreg_data);
+ if (ret < 0) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
+ {
+ .compatible = "qcom,pm8005-rpmh-regulators",
+ .data = pm8005_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8009-rpmh-regulators",
+ .data = pm8009_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8009-1-rpmh-regulators",
+ .data = pm8009_1_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8010-rpmh-regulators",
+ .data = pm8010_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8150-rpmh-regulators",
+ .data = pm8150_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8150l-rpmh-regulators",
+ .data = pm8150l_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8350-rpmh-regulators",
+ .data = pm8350_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8350c-rpmh-regulators",
+ .data = pm8350c_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8450-rpmh-regulators",
+ .data = pm8450_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8550-rpmh-regulators",
+ .data = pm8550_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8550ve-rpmh-regulators",
+ .data = pm8550ve_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8550vs-rpmh-regulators",
+ .data = pm8550vs_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm8998-rpmh-regulators",
+ .data = pm8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmg1110-rpmh-regulators",
+ .data = pmg1110_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmi8998-rpmh-regulators",
+ .data = pmi8998_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm6150-rpmh-regulators",
+ .data = pm6150_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm6150l-rpmh-regulators",
+ .data = pm6150l_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm6350-rpmh-regulators",
+ .data = pm6350_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmc8180-rpmh-regulators",
+ .data = pm8150_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmc8180c-rpmh-regulators",
+ .data = pm8150l_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmc8380-rpmh-regulators",
+ .data = pmc8380_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmm8155au-rpmh-regulators",
+ .data = pmm8155au_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmm8654au-rpmh-regulators",
+ .data = pmm8654au_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmx55-rpmh-regulators",
+ .data = pmx55_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmx65-rpmh-regulators",
+ .data = pmx65_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmx75-rpmh-regulators",
+ .data = pmx75_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm7325-rpmh-regulators",
+ .data = pm7325_vreg_data,
+ },
+ {
+ .compatible = "qcom,pmr735a-rpmh-regulators",
+ .data = pmr735a_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm660-rpmh-regulators",
+ .data = pm660_vreg_data,
+ },
+ {
+ .compatible = "qcom,pm660l-rpmh-regulators",
+ .data = pm660l_vreg_data,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
+
+static struct platform_driver rpmh_regulator_driver = {
+ .driver = {
+ .name = "qcom-rpmh-regulator",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = of_match_ptr(rpmh_regulator_match_table),
+ },
+ .probe = rpmh_regulator_probe,
+};
+module_platform_driver(rpmh_regulator_driver);
+
+MODULE_DESCRIPTION("Qualcomm RPMh regulator driver");
+MODULE_LICENSE("GPL v2");
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 17/24] power: regulator: qcom-rpmh-regulator: adjust headers for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (15 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 16/24] power: regulator: import qcom-rpmh-regulator from Linux Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 18/24] power: regulator: qcom-rpmh-regulator: port over lineage_range helpers Caleb Connolly
` (7 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Remove unused/unsupported Linux headers and add necessary U-Boot ones.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 80e304711345..5f522de44734 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -4,17 +4,14 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/of_regulator.h>
+#include <dm/device_compat.h>
+#include <dm/device.h>
+#include <dm/devres.h>
+#include <dm/lists.h>
+#include <power/regulator.h>
+#include <log.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/rpmh.h>
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 18/24] power: regulator: qcom-rpmh-regulator: port over lineage_range helpers
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (16 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 17/24] power: regulator: qcom-rpmh-regulator: adjust headers for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 19/24] power: regulator: qcom-rpmh-regulator: adjust structs for U-Boot Caleb Connolly
` (6 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Import struct linear_range() and builder macro from Linux regulator
core.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 37 +++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 5f522de44734..d0acee9f558e 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -28,8 +28,15 @@ enum rpmh_regulator_type {
VRM,
XOB,
};
+enum rpmh_regulator_mode {
+ REGULATOR_MODE_RETENTION,
+ REGULATOR_MODE_LPM,
+ REGULATOR_MODE_AUTO,
+ REGULATOR_MODE_HPM,
+};
+
#define RPMH_REGULATOR_REG_VRM_VOLTAGE 0x0
#define RPMH_REGULATOR_REG_ENABLE 0x4
#define RPMH_REGULATOR_REG_VRM_MODE 0x8
@@ -60,8 +67,38 @@ enum rpmh_regulator_type {
#define PMIC5_BOB_MODE_PFM 4
#define PMIC5_BOB_MODE_AUTO 6
#define PMIC5_BOB_MODE_PWM 7
+
+/**
+ * struct linear_range - table of selector - value pairs
+ *
+ * Define a lookup-table for range of values. Intended to help when looking
+ * for a register value matching certaing physical measure (like voltage).
+ * Usable when increment of one in register always results a constant increment
+ * of the physical measure (like voltage).
+ *
+ * @min: Lowest value in range
+ * @min_sel: Lowest selector for range
+ * @max_sel: Highest selector for range
+ * @step: Value step size
+ */
+struct linear_range {
+ unsigned int min;
+ unsigned int min_sel;
+ unsigned int max_sel;
+ unsigned int step;
+};
+
+/* Initialize struct linear_range for regulators */
+#define REGULATOR_LINEAR_RANGE(_min_uV, _min_sel, _max_sel, _step_uV) \
+{ \
+ .min = _min_uV, \
+ .min_sel = _min_sel, \
+ .max_sel = _max_sel, \
+ .step = _step_uV, \
+}
+
/**
* struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
* @regulator_type: RPMh accelerator type used to manage this
* regulator
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 19/24] power: regulator: qcom-rpmh-regulator: adjust structs for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (17 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 18/24] power: regulator: qcom-rpmh-regulator: port over lineage_range helpers Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 20/24] power: regulator: qcom-rpmh-regulator: remove unused regulators Caleb Connolly
` (5 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Switch to our linear_range helpers and remove unused/unsupported
linux-isms.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 28 +++++++++++++--------------
1 file changed, 13 insertions(+), 15 deletions(-)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index d0acee9f558e..089623f3a2b9 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -102,13 +102,12 @@ struct linear_range {
* struct rpmh_vreg_hw_data - RPMh regulator hardware configurations
* @regulator_type: RPMh accelerator type used to manage this
* regulator
* @ops: Pointer to regulator ops callback structure
- * @voltage_ranges: The possible ranges of voltages supported by this
- * PMIC regulator type
- * @n_linear_ranges: Number of entries in voltage_ranges
+ * @voltage_range: The single range of voltages supported by this
+ * PMIC regulator type
* @n_voltages: The number of unique voltage set points defined
- * by voltage_ranges
+ * by voltage_range
* @hpm_min_load_uA: Minimum load current in microamps that requires
* high power mode (HPM) operation. This is used
* for LDO hardware type regulators only.
* @pmic_mode_map: Array indexed by regulator framework mode
@@ -119,15 +118,15 @@ struct linear_range {
* in device tree to a regulator framework mode
*/
struct rpmh_vreg_hw_data {
enum rpmh_regulator_type regulator_type;
- const struct regulator_ops *ops;
- const struct linear_range *voltage_ranges;
- int n_linear_ranges;
+ const struct dm_regulator_ops *ops;
+ struct linear_range voltage_range;
int n_voltages;
int hpm_min_load_uA;
- const int *pmic_mode_map;
- unsigned int (*of_map_mode)(unsigned int mode);
+ struct dm_regulator_mode *pmic_mode_map;
+ int n_modes;
+ unsigned int (*of_map_mode)(unsigned int mode);
};
/**
* struct rpmh_vreg - individual RPMh regulator data structure encapsulating a
@@ -148,23 +147,22 @@ struct rpmh_vreg_hw_data {
* not
* @bypassed: Boolean indicating if the regulator is in
* bypass (pass-through) mode or not. This is
* only used by BOB rpmh-regulator resources.
- * @voltage_selector: Selector used for get_voltage_sel() and
- * set_voltage_sel() callbacks
+ * @uv: Selector used for get_voltage_sel() and
+ * set_value() callbacks
* @mode: RPMh VRM regulator current framework mode
*/
struct rpmh_vreg {
- struct device *dev;
+ struct udevice *dev;
u32 addr;
- struct regulator_desc rdesc;
const struct rpmh_vreg_hw_data *hw_data;
bool always_wait_for_ack;
int enabled;
bool bypassed;
- int voltage_selector;
- unsigned int mode;
+ int uv;
+ int mode;
};
/**
* struct rpmh_vreg_init_data - initialization data for an RPMh regulator
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 20/24] power: regulator: qcom-rpmh-regulator: remove unused regulators
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (18 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 19/24] power: regulator: qcom-rpmh-regulator: adjust structs for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 21/24] power: regulator: qcom-rpmh-regulator: port ops to U-Boot Caleb Connolly
` (4 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Initially just include the few regulators needed for the RB5 board.
Others can be added back as-needed.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 1281 -------------------------
1 file changed, 1281 deletions(-)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 089623f3a2b9..2a8e8f9ac444 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -338,68 +338,8 @@ static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev)
return vreg->mode;
}
-/**
- * rpmh_regulator_vrm_get_optimum_mode() - get the mode based on the load
- * @rdev: Regulator device pointer for the rpmh-regulator
- * @input_uV: Input voltage
- * @output_uV: Output voltage
- * @load_uA: Aggregated load current in microamps
- *
- * This function is used in the regulator_ops for VRM type RPMh regulator
- * devices.
- *
- * Return: 0 on success, errno on failure
- */
-static unsigned int rpmh_regulator_vrm_get_optimum_mode(
- struct regulator_dev *rdev, int input_uV, int output_uV, int load_uA)
-{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
-
- if (load_uA >= vreg->hw_data->hpm_min_load_uA)
- return REGULATOR_MODE_NORMAL;
- else
- return REGULATOR_MODE_IDLE;
-}
-
-static int rpmh_regulator_vrm_set_bypass(struct regulator_dev *rdev,
- bool enable)
-{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
- int ret;
-
- if (vreg->bypassed == enable)
- return 0;
-
- ret = rpmh_regulator_vrm_set_mode_bypass(vreg, vreg->mode, enable);
- if (!ret)
- vreg->bypassed = enable;
-
- return ret;
-}
-
-static int rpmh_regulator_vrm_get_bypass(struct regulator_dev *rdev,
- bool *enable)
-{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
-
- *enable = vreg->bypassed;
-
- return 0;
-}
-
-static const struct regulator_ops rpmh_regulator_vrm_ops = {
- .enable = rpmh_regulator_enable,
- .disable = rpmh_regulator_disable,
- .is_enabled = rpmh_regulator_is_enabled,
- .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
- .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_mode = rpmh_regulator_vrm_set_mode,
- .get_mode = rpmh_regulator_vrm_get_mode,
-};
-
static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
.enable = rpmh_regulator_enable,
.disable = rpmh_regulator_disable,
.is_enabled = rpmh_regulator_is_enabled,
@@ -410,331 +350,8 @@ static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
.get_mode = rpmh_regulator_vrm_get_mode,
.get_optimum_mode = rpmh_regulator_vrm_get_optimum_mode,
};
-static const struct regulator_ops rpmh_regulator_vrm_bypass_ops = {
- .enable = rpmh_regulator_enable,
- .disable = rpmh_regulator_disable,
- .is_enabled = rpmh_regulator_is_enabled,
- .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
- .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_mode = rpmh_regulator_vrm_set_mode,
- .get_mode = rpmh_regulator_vrm_get_mode,
- .set_bypass = rpmh_regulator_vrm_set_bypass,
- .get_bypass = rpmh_regulator_vrm_get_bypass,
-};
-
-static const struct regulator_ops rpmh_regulator_xob_ops = {
- .enable = rpmh_regulator_enable,
- .disable = rpmh_regulator_disable,
- .is_enabled = rpmh_regulator_is_enabled,
-};
-
-/**
- * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
- * @vreg: Pointer to the individual rpmh-regulator resource
- * @dev: Pointer to the top level rpmh-regulator PMIC device
- * @node: Pointer to the individual rpmh-regulator resource
- * device node
- * @pmic_id: String used to identify the top level rpmh-regulator
- * PMIC device on the board
- * @pmic_rpmh_data: Pointer to a null-terminated array of rpmh-regulator
- * resources defined for the top level PMIC device
- *
- * Return: 0 on success, errno on failure
- */
-static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
- struct device_node *node, const char *pmic_id,
- const struct rpmh_vreg_init_data *pmic_rpmh_data)
-{
- struct regulator_config reg_config = {};
- char rpmh_resource_name[20] = "";
- const struct rpmh_vreg_init_data *rpmh_data;
- struct regulator_init_data *init_data;
- struct regulator_dev *rdev;
- int ret;
-
- vreg->dev = dev;
-
- for (rpmh_data = pmic_rpmh_data; rpmh_data->name; rpmh_data++)
- if (of_node_name_eq(node, rpmh_data->name))
- break;
-
- if (!rpmh_data->name) {
- dev_err(dev, "Unknown regulator %pOFn\n", node);
- return -EINVAL;
- }
-
- scnprintf(rpmh_resource_name, sizeof(rpmh_resource_name),
- rpmh_data->resource_name, pmic_id);
-
- vreg->addr = cmd_db_read_addr(rpmh_resource_name);
- if (!vreg->addr) {
- dev_err(dev, "%pOFn: could not find RPMh address for resource %s\n",
- node, rpmh_resource_name);
- return -ENODEV;
- }
-
- vreg->rdesc.name = rpmh_data->name;
- vreg->rdesc.supply_name = rpmh_data->supply_name;
- vreg->hw_data = rpmh_data->hw_data;
-
- vreg->enabled = -EINVAL;
- vreg->voltage_selector = -ENOTRECOVERABLE;
- vreg->mode = REGULATOR_MODE_INVALID;
-
- if (rpmh_data->hw_data->n_voltages) {
- vreg->rdesc.linear_ranges = rpmh_data->hw_data->voltage_ranges;
- vreg->rdesc.n_linear_ranges = rpmh_data->hw_data->n_linear_ranges;
- vreg->rdesc.n_voltages = rpmh_data->hw_data->n_voltages;
- }
-
- vreg->always_wait_for_ack = of_property_read_bool(node,
- "qcom,always-wait-for-ack");
-
- vreg->rdesc.owner = THIS_MODULE;
- vreg->rdesc.type = REGULATOR_VOLTAGE;
- vreg->rdesc.ops = vreg->hw_data->ops;
- vreg->rdesc.of_map_mode = vreg->hw_data->of_map_mode;
-
- init_data = of_get_regulator_init_data(dev, node, &vreg->rdesc);
- if (!init_data)
- return -ENOMEM;
-
- if (rpmh_data->hw_data->regulator_type == XOB &&
- init_data->constraints.min_uV &&
- init_data->constraints.min_uV == init_data->constraints.max_uV) {
- vreg->rdesc.fixed_uV = init_data->constraints.min_uV;
- vreg->rdesc.n_voltages = 1;
- }
-
- reg_config.dev = dev;
- reg_config.init_data = init_data;
- reg_config.of_node = node;
- reg_config.driver_data = vreg;
-
- rdev = devm_regulator_register(dev, &vreg->rdesc, ®_config);
- if (IS_ERR(rdev)) {
- ret = PTR_ERR(rdev);
- dev_err(dev, "%pOFn: devm_regulator_register() failed, ret=%d\n",
- node, ret);
- return ret;
- }
-
- dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
- node, rpmh_resource_name, vreg->addr);
-
- return 0;
-}
-
-static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = PMIC4_LDO_MODE_RETENTION,
- [REGULATOR_MODE_IDLE] = PMIC4_LDO_MODE_LPM,
- [REGULATOR_MODE_NORMAL] = PMIC4_LDO_MODE_HPM,
- [REGULATOR_MODE_FAST] = -EINVAL,
-};
-
-static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = PMIC5_LDO_MODE_RETENTION,
- [REGULATOR_MODE_IDLE] = PMIC5_LDO_MODE_LPM,
- [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM,
- [REGULATOR_MODE_FAST] = -EINVAL,
-};
-
-static const int pmic_mode_map_pmic5_ldo_hpm[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = -EINVAL,
- [REGULATOR_MODE_IDLE] = -EINVAL,
- [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM,
- [REGULATOR_MODE_FAST] = -EINVAL,
-};
-
-static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode)
-{
- unsigned int mode;
-
- switch (rpmh_mode) {
- case RPMH_REGULATOR_MODE_HPM:
- mode = REGULATOR_MODE_NORMAL;
- break;
- case RPMH_REGULATOR_MODE_LPM:
- mode = REGULATOR_MODE_IDLE;
- break;
- case RPMH_REGULATOR_MODE_RET:
- mode = REGULATOR_MODE_STANDBY;
- break;
- default:
- mode = REGULATOR_MODE_INVALID;
- break;
- }
-
- return mode;
-}
-
-static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = PMIC4_SMPS_MODE_RETENTION,
- [REGULATOR_MODE_IDLE] = PMIC4_SMPS_MODE_PFM,
- [REGULATOR_MODE_NORMAL] = PMIC4_SMPS_MODE_AUTO,
- [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM,
-};
-
-static const int pmic_mode_map_pmic5_smps[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = PMIC5_SMPS_MODE_RETENTION,
- [REGULATOR_MODE_IDLE] = PMIC5_SMPS_MODE_PFM,
- [REGULATOR_MODE_NORMAL] = PMIC5_SMPS_MODE_AUTO,
- [REGULATOR_MODE_FAST] = PMIC5_SMPS_MODE_PWM,
-};
-
-static unsigned int
-rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode)
-{
- unsigned int mode;
-
- switch (rpmh_mode) {
- case RPMH_REGULATOR_MODE_HPM:
- mode = REGULATOR_MODE_FAST;
- break;
- case RPMH_REGULATOR_MODE_AUTO:
- mode = REGULATOR_MODE_NORMAL;
- break;
- case RPMH_REGULATOR_MODE_LPM:
- mode = REGULATOR_MODE_IDLE;
- break;
- case RPMH_REGULATOR_MODE_RET:
- mode = REGULATOR_MODE_STANDBY;
- break;
- default:
- mode = REGULATOR_MODE_INVALID;
- break;
- }
-
- return mode;
-}
-
-static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = -EINVAL,
- [REGULATOR_MODE_IDLE] = PMIC4_BOB_MODE_PFM,
- [REGULATOR_MODE_NORMAL] = PMIC4_BOB_MODE_AUTO,
- [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM,
-};
-
-static const int pmic_mode_map_pmic5_bob[REGULATOR_MODE_STANDBY + 1] = {
- [REGULATOR_MODE_INVALID] = -EINVAL,
- [REGULATOR_MODE_STANDBY] = -EINVAL,
- [REGULATOR_MODE_IDLE] = PMIC5_BOB_MODE_PFM,
- [REGULATOR_MODE_NORMAL] = PMIC5_BOB_MODE_AUTO,
- [REGULATOR_MODE_FAST] = PMIC5_BOB_MODE_PWM,
-};
-
-static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode)
-{
- unsigned int mode;
-
- switch (rpmh_mode) {
- case RPMH_REGULATOR_MODE_HPM:
- mode = REGULATOR_MODE_FAST;
- break;
- case RPMH_REGULATOR_MODE_AUTO:
- mode = REGULATOR_MODE_NORMAL;
- break;
- case RPMH_REGULATOR_MODE_LPM:
- mode = REGULATOR_MODE_IDLE;
- break;
- default:
- mode = REGULATOR_MODE_INVALID;
- break;
- }
-
- return mode;
-}
-
-static const struct rpmh_vreg_hw_data pmic4_pldo = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1664000, 0, 255, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 256,
- .hpm_min_load_uA = 10000,
- .pmic_mode_map = pmic_mode_map_pmic4_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_pldo_lv = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1256000, 0, 127, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 128,
- .hpm_min_load_uA = 10000,
- .pmic_mode_map = pmic_mode_map_pmic4_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_nldo = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(312000, 0, 127, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 128,
- .hpm_min_load_uA = 30000,
- .pmic_mode_map = pmic_mode_map_pmic4_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_hfsmps3 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 216,
- .pmic_mode_map = pmic_mode_map_pmic4_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_ftsmps426 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 258, 4000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 259,
- .pmic_mode_map = pmic_mode_map_pmic4_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_bob = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_bypass_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1824000, 0, 83, 32000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 84,
- .pmic_mode_map = pmic_mode_map_pmic4_bob,
- .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic4_lvs = {
- .regulator_type = XOB,
- .ops = &rpmh_regulator_xob_ops,
- /* LVS hardware does not support voltage or mode configuration. */
-};
-
static const struct rpmh_vreg_hw_data pmic5_pldo = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
.voltage_ranges = (struct linear_range[]) {
@@ -759,810 +376,24 @@ static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
.pmic_mode_map = pmic_mode_map_pmic5_ldo,
.of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
};
-static const struct rpmh_vreg_hw_data pmic5_pldo515_mv = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1800000, 0, 187, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 188,
- .hpm_min_load_uA = 10000,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_pldo502 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 256,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_pldo502ln = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1800000, 0, 2, 200000),
- REGULATOR_LINEAR_RANGE(2608000, 3, 28, 16000),
- REGULATOR_LINEAR_RANGE(3104000, 29, 30, 96000),
- REGULATOR_LINEAR_RANGE(3312000, 31, 31, 0),
- },
- .n_linear_ranges = 4,
- .n_voltages = 32,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo_hpm,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_nldo = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 124,
- .hpm_min_load_uA = 30000,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_nldo515 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 210, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 211,
- .hpm_min_load_uA = 30000,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_nldo502 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(528000, 0, 127, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 128,
- .hpm_min_load_uA = 30000,
- .pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 216,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 264,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps520 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 264,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps525_lv = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(300000, 0, 267, 4000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 268,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps525_mv = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(600000, 0, 267, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 268,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_ftsmps527 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 215,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(320000, 0, 235, 16000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 236,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_hfsmps515_1 = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(900000, 0, 4, 16000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 5,
- .pmic_mode_map = pmic_mode_map_pmic5_smps,
- .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode,
-};
-
-static const struct rpmh_vreg_hw_data pmic5_bob = {
- .regulator_type = VRM,
- .ops = &rpmh_regulator_vrm_bypass_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(3000000, 0, 31, 32000),
- },
- .n_linear_ranges = 1,
- .n_voltages = 32,
- .pmic_mode_map = pmic_mode_map_pmic5_bob,
- .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode,
-};
-
#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
{ \
.name = _name, \
.resource_name = _resource_name, \
.hw_data = _hw_data, \
.supply_name = _supply_name, \
}
-static const struct rpmh_vreg_init_data pm8998_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_hfsmps3, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic4_ftsmps426, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic4_ftsmps426, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic4_ftsmps426, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic4_ftsmps426, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic4_ftsmps426, "vdd-s10"),
- RPMH_VREG("smps11", "smp%s11", &pmic4_ftsmps426, "vdd-s11"),
- RPMH_VREG("smps12", "smp%s12", &pmic4_ftsmps426, "vdd-s12"),
- RPMH_VREG("smps13", "smp%s13", &pmic4_ftsmps426, "vdd-s13"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l27"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l3-l11"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic4_nldo, "vdd-l4-l5"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l4-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo, "vdd-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic4_nldo, "vdd-l3-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l16-l28"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic4_nldo, "vdd-l2-l8-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l18-l22"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic4_pldo, "vdd-l20-l24"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic4_pldo, "vdd-l13-l19-l21"),
- RPMH_VREG("ldo22", "ldo%s22", &pmic4_pldo, "vdd-l18-l22"),
- RPMH_VREG("ldo23", "ldo%s23", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo24", "ldo%s24", &pmic4_pldo, "vdd-l20-l24"),
- RPMH_VREG("ldo25", "ldo%s25", &pmic4_pldo, "vdd-l10-l23-l25"),
- RPMH_VREG("ldo26", "ldo%s26", &pmic4_nldo, "vdd-l26"),
- RPMH_VREG("ldo27", "ldo%s27", &pmic4_nldo, "vdd-l1-l27"),
- RPMH_VREG("ldo28", "ldo%s28", &pmic4_pldo, "vdd-l16-l28"),
- RPMH_VREG("lvs1", "vs%s1", &pmic4_lvs, "vin-lvs-1-2"),
- RPMH_VREG("lvs2", "vs%s2", &pmic4_lvs, "vin-lvs-1-2"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmg1110_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmi8998_vreg_data[] = {
- RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8005_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_ftsmps426, "vdd-s4"),
- {}
-};
-
static const struct rpmh_vreg_init_data pm8150_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
{}
};
static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmm8155au_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l16-l17"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmm8654au_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps527, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps527, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps527, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps527, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps527, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps527, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps527, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps527, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps527, "vdd-s9"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo515, "vdd-s9"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo515, "vdd-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo515_mv, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8350_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_hfsmps510, "vdd-s10"),
- RPMH_VREG("smps11", "smp%s11", &pmic5_hfsmps510, "vdd-s11"),
- RPMH_VREG("smps12", "smp%s12", &pmic5_hfsmps510, "vdd-s12"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l5"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8350c_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps515, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l12"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo_lv, "vdd-l2-l8"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l2-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l6-l9-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l1-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l3-l4-l5-l7-l13"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8450_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8550_vreg_data[] = {
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo515, "vdd-l1-l4-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo515, "vdd-l11"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, "vdd-l2-l13-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l17"),
- RPMH_VREG("bob1", "bob%s1", &pmic5_bob, "vdd-bob1"),
- RPMH_VREG("bob2", "bob%s2", &pmic5_bob, "vdd-bob2"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8550vs_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_lv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_mv, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8550ve_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmc8380_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8009_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8009_1_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515_1, "vdd-s2"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo_lv, "vdd-l7"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm8010_vreg_data[] = {
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo502, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo502, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo502ln, "vdd-l3-l4"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo502ln, "vdd-l3-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo502, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo502ln, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo502, "vdd-l7"),
-};
-
-static const struct rpmh_vreg_init_data pm6150_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l4-l7-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo_lv, "vdd-l11-l12-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l10-l14-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo, "vdd-l5-l16-l17-l18-l19"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm6150l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, "vdd-l1-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
- RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm6350_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, NULL),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, NULL),
- /* smps3 - smps5 not configured */
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, NULL),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, NULL),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_pldo, NULL),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, NULL),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, NULL),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, NULL),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, NULL),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo, NULL),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, NULL),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, NULL),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, NULL),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo, NULL),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, NULL),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo, NULL),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, NULL),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, NULL),
- /* ldo17 not configured */
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, NULL),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, NULL),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, NULL),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, NULL),
- RPMH_VREG("ldo22", "ldo%s22", &pmic5_nldo, NULL),
-};
-
-static const struct rpmh_vreg_init_data pmx55_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l9"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4-l12"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l7-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l3-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l4-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l10-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l16"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmx65_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps510, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps510, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_hfsmps510, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l18"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo, "vdd-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l5-l6-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo, "vdd-l17"),
- /* ldo18 not configured */
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo, "vdd-l19"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo, "vdd-l20"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo, "vdd-l21"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmx75_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps525_lv, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps525_lv, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps525_lv, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps525_mv, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps525_lv, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps525_lv, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps525_lv, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps525_lv, "vdd-s8"),
- RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps525_lv, "vdd-s9"),
- RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps525_lv, "vdd-s10"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo515, "vdd-l1"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo515, "vdd-l2-18"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo515, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo515, "vdd-l4-l16"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo_lv, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo_lv, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_nldo515, "vdd-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo515, "vdd-l8-l9"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo515, "vdd-l8-l9"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo515, "vdd-l12"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l11-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo515, "vdd-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo515, "vdd-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo515, "vdd-l4-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_nldo515, "vdd-l17"),
- /* ldo18 not configured */
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_nldo515, "vdd-l19"),
- RPMH_VREG("ldo20", "ldo%s20", &pmic5_nldo515, "vdd-l20-l21"),
- RPMH_VREG("ldo21", "ldo%s21", &pmic5_nldo515, "vdd-l20-l21"),
-};
-
-static const struct rpmh_vreg_init_data pm7325_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps520, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps520, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps520, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps520, "vdd-s6"),
- RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps520, "vdd-s7"),
- RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l2-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l8"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic5_nldo, "vdd-l6-l9-l10"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic5_nldo, "vdd-l13"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic5_nldo, "vdd-l14-l16"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic5_nldo, "vdd-l1-l4-l12-l15"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic5_nldo, "vdd-l14-l16"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic5_pldo_lv, "vdd-l11-l17-l18-l19"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pmr735a_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps520, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps520, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic5_hfsmps515, "vdd-s3"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l1-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo_lv, "vdd-l4"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l5-l6"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l5-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-bob"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm660_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3"),
- RPMH_VREG("smps4", "smp%s4", &pmic4_hfsmps3, "vdd-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_hfsmps3, "vdd-s5"),
- RPMH_VREG("smps6", "smp%s6", &pmic4_hfsmps3, "vdd-s6"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_nldo, "vdd-l2-l3"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_nldo, "vdd-l2-l3"),
- /* ldo4 is inaccessible on PM660 */
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_nldo, "vdd-l5"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_nldo, "vdd-l1-l6-l7"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo9", "ldo%s9", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo10", "ldo%s10", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo11", "ldo%s11", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo12", "ldo%s12", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo13", "ldo%s13", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo14", "ldo%s14", &pmic4_pldo_lv, "vdd-l8-l9-l10-l11-l12-l13-l14"),
- RPMH_VREG("ldo15", "ldo%s15", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo16", "ldo%s16", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo17", "ldo%s17", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo18", "ldo%s18", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- RPMH_VREG("ldo19", "ldo%s19", &pmic4_pldo, "vdd-l15-l16-l17-l18-l19"),
- {}
-};
-
-static const struct rpmh_vreg_init_data pm660l_vreg_data[] = {
- RPMH_VREG("smps1", "smp%s1", &pmic4_ftsmps426, "vdd-s1"),
- RPMH_VREG("smps2", "smp%s2", &pmic4_ftsmps426, "vdd-s2"),
- RPMH_VREG("smps3", "smp%s3", &pmic4_ftsmps426, "vdd-s3-s4"),
- RPMH_VREG("smps5", "smp%s5", &pmic4_ftsmps426, "vdd-s5"),
- RPMH_VREG("ldo1", "ldo%s1", &pmic4_nldo, "vdd-l1-l9-l10"),
- RPMH_VREG("ldo2", "ldo%s2", &pmic4_pldo, "vdd-l2"),
- RPMH_VREG("ldo3", "ldo%s3", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo4", "ldo%s4", &pmic4_pldo, "vdd-l4-l6"),
- RPMH_VREG("ldo5", "ldo%s5", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo6", "ldo%s6", &pmic4_pldo, "vdd-l4-l6"),
- RPMH_VREG("ldo7", "ldo%s7", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("ldo8", "ldo%s8", &pmic4_pldo, "vdd-l3-l5-l7-l8"),
- RPMH_VREG("bob", "bob%s1", &pmic4_bob, "vdd-bob"),
{}
};
static int rpmh_regulator_probe(struct platform_device *pdev)
@@ -1602,128 +433,16 @@ static int rpmh_regulator_probe(struct platform_device *pdev)
return 0;
}
static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
- {
- .compatible = "qcom,pm8005-rpmh-regulators",
- .data = pm8005_vreg_data,
- },
- {
- .compatible = "qcom,pm8009-rpmh-regulators",
- .data = pm8009_vreg_data,
- },
- {
- .compatible = "qcom,pm8009-1-rpmh-regulators",
- .data = pm8009_1_vreg_data,
- },
- {
- .compatible = "qcom,pm8010-rpmh-regulators",
- .data = pm8010_vreg_data,
- },
{
.compatible = "qcom,pm8150-rpmh-regulators",
.data = pm8150_vreg_data,
},
{
.compatible = "qcom,pm8150l-rpmh-regulators",
.data = pm8150l_vreg_data,
},
- {
- .compatible = "qcom,pm8350-rpmh-regulators",
- .data = pm8350_vreg_data,
- },
- {
- .compatible = "qcom,pm8350c-rpmh-regulators",
- .data = pm8350c_vreg_data,
- },
- {
- .compatible = "qcom,pm8450-rpmh-regulators",
- .data = pm8450_vreg_data,
- },
- {
- .compatible = "qcom,pm8550-rpmh-regulators",
- .data = pm8550_vreg_data,
- },
- {
- .compatible = "qcom,pm8550ve-rpmh-regulators",
- .data = pm8550ve_vreg_data,
- },
- {
- .compatible = "qcom,pm8550vs-rpmh-regulators",
- .data = pm8550vs_vreg_data,
- },
- {
- .compatible = "qcom,pm8998-rpmh-regulators",
- .data = pm8998_vreg_data,
- },
- {
- .compatible = "qcom,pmg1110-rpmh-regulators",
- .data = pmg1110_vreg_data,
- },
- {
- .compatible = "qcom,pmi8998-rpmh-regulators",
- .data = pmi8998_vreg_data,
- },
- {
- .compatible = "qcom,pm6150-rpmh-regulators",
- .data = pm6150_vreg_data,
- },
- {
- .compatible = "qcom,pm6150l-rpmh-regulators",
- .data = pm6150l_vreg_data,
- },
- {
- .compatible = "qcom,pm6350-rpmh-regulators",
- .data = pm6350_vreg_data,
- },
- {
- .compatible = "qcom,pmc8180-rpmh-regulators",
- .data = pm8150_vreg_data,
- },
- {
- .compatible = "qcom,pmc8180c-rpmh-regulators",
- .data = pm8150l_vreg_data,
- },
- {
- .compatible = "qcom,pmc8380-rpmh-regulators",
- .data = pmc8380_vreg_data,
- },
- {
- .compatible = "qcom,pmm8155au-rpmh-regulators",
- .data = pmm8155au_vreg_data,
- },
- {
- .compatible = "qcom,pmm8654au-rpmh-regulators",
- .data = pmm8654au_vreg_data,
- },
- {
- .compatible = "qcom,pmx55-rpmh-regulators",
- .data = pmx55_vreg_data,
- },
- {
- .compatible = "qcom,pmx65-rpmh-regulators",
- .data = pmx65_vreg_data,
- },
- {
- .compatible = "qcom,pmx75-rpmh-regulators",
- .data = pmx75_vreg_data,
- },
- {
- .compatible = "qcom,pm7325-rpmh-regulators",
- .data = pm7325_vreg_data,
- },
- {
- .compatible = "qcom,pmr735a-rpmh-regulators",
- .data = pmr735a_vreg_data,
- },
- {
- .compatible = "qcom,pm660-rpmh-regulators",
- .data = pm660_vreg_data,
- },
- {
- .compatible = "qcom,pm660l-rpmh-regulators",
- .data = pm660l_vreg_data,
- },
{}
};
MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 21/24] power: regulator: qcom-rpmh-regulator: port ops to U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (19 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 20/24] power: regulator: qcom-rpmh-regulator: remove unused regulators Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 22/24] power: regulator: qcom-rpmh-regulator: adjust probe for U-Boot Caleb Connolly
` (3 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Port over the regulator ops to U-Boot's regulator API. Add back the
pmic5 mode map using U-Boot dm_regulator_mode API and adjust the
pmic5_pldo and pmic5_pldo_lv definitions. No functional changes.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 158 ++++++++++++++------------
1 file changed, 87 insertions(+), 71 deletions(-)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index 2a8e8f9ac444..b716b380c148 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -192,87 +192,96 @@ struct rpmh_vreg_init_data {
*
* Return: 0 on success, errno on failure
*/
static int rpmh_regulator_send_request(struct rpmh_vreg *vreg,
- struct tcs_cmd *cmd, bool wait_for_ack)
+ const struct tcs_cmd *cmd, bool wait_for_ack)
{
int ret;
if (wait_for_ack || vreg->always_wait_for_ack)
- ret = rpmh_write(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
+ ret = rpmh_write(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
else
- ret = rpmh_write_async(vreg->dev, RPMH_ACTIVE_ONLY_STATE, cmd,
- 1);
+ ret = rpmh_write_async(vreg->dev->parent, RPMH_ACTIVE_ONLY_STATE, cmd, 1);
return ret;
}
-static int _rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector, bool wait_for_ack)
+static int _rpmh_regulator_vrm_set_value(struct udevice *rdev,
+ int uv, bool wait_for_ack)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
struct tcs_cmd cmd = {
.addr = vreg->addr + RPMH_REGULATOR_REG_VRM_VOLTAGE,
};
int ret;
+ unsigned int selector;
- /* VRM voltage control register is set with voltage in millivolts. */
- cmd.data = DIV_ROUND_UP(regulator_list_voltage_linear_range(rdev,
- selector), 1000);
+ selector = (uv - vreg->hw_data->voltage_range.min) / vreg->hw_data->voltage_range.step;
+ cmd.data = DIV_ROUND_UP(vreg->hw_data->voltage_range.min +
+ selector * vreg->hw_data->voltage_range.step, 1000);
ret = rpmh_regulator_send_request(vreg, &cmd, wait_for_ack);
if (!ret)
- vreg->voltage_selector = selector;
+ vreg->uv = cmd.data * 1000;
return ret;
}
-static int rpmh_regulator_vrm_set_voltage_sel(struct regulator_dev *rdev,
- unsigned int selector)
+static int rpmh_regulator_vrm_set_value(struct udevice *rdev,
+ int uv)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
+
+ debug("%s: set_value %d (current %d)\n", rdev->name, uv, vreg->uv);
if (vreg->enabled == -EINVAL) {
/*
* Cache the voltage and send it later when the regulator is
* enabled or disabled.
*/
- vreg->voltage_selector = selector;
+ vreg->uv = uv;
return 0;
}
- return _rpmh_regulator_vrm_set_voltage_sel(rdev, selector,
- selector > vreg->voltage_selector);
+ return _rpmh_regulator_vrm_set_value(rdev, uv,
+ uv > vreg->uv);
}
-static int rpmh_regulator_vrm_get_voltage_sel(struct regulator_dev *rdev)
+static int rpmh_regulator_vrm_get_value(struct udevice *rdev)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
- return vreg->voltage_selector;
+ debug("%s: get_value %d\n", rdev->name, vreg->uv);
+
+ return vreg->uv;
}
-static int rpmh_regulator_is_enabled(struct regulator_dev *rdev)
+static int rpmh_regulator_is_enabled(struct udevice *rdev)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
- return vreg->enabled;
+ debug("%s: is_enabled %d\n", rdev->name, vreg->enabled);
+
+ return vreg->enabled > 0;
}
-static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
- bool enable)
+static int rpmh_regulator_set_enable_state(struct udevice *rdev,
+ bool enable)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
struct tcs_cmd cmd = {
.addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
.data = enable,
};
int ret;
+ debug("%s: set_enable %d (current %d)\n", rdev->name, enable,
+ vreg->enabled);
+
if (vreg->enabled == -EINVAL &&
- vreg->voltage_selector != -ENOTRECOVERABLE) {
- ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
- vreg->voltage_selector, true);
+ vreg->uv != -ENOTRECOVERABLE) {
+ ret = _rpmh_regulator_vrm_set_value(rdev,
+ vreg->uv, true);
if (ret < 0)
return ret;
}
@@ -282,47 +291,46 @@ static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
return ret;
}
-static int rpmh_regulator_enable(struct regulator_dev *rdev)
-{
- return rpmh_regulator_set_enable_state(rdev, true);
-}
-
-static int rpmh_regulator_disable(struct regulator_dev *rdev)
-{
- return rpmh_regulator_set_enable_state(rdev, false);
-}
-
static int rpmh_regulator_vrm_set_mode_bypass(struct rpmh_vreg *vreg,
- unsigned int mode, bool bypassed)
+ unsigned int mode, bool bypassed)
{
struct tcs_cmd cmd = {
.addr = vreg->addr + RPMH_REGULATOR_REG_VRM_MODE,
};
- int pmic_mode;
+ struct dm_regulator_mode *pmic_mode;
+ int i;
- if (mode > REGULATOR_MODE_STANDBY)
+ if (mode > REGULATOR_MODE_HPM)
return -EINVAL;
- pmic_mode = vreg->hw_data->pmic_mode_map[mode];
- if (pmic_mode < 0)
- return pmic_mode;
+ for (i = 0; i < vreg->hw_data->n_modes; i++) {
+ pmic_mode = &vreg->hw_data->pmic_mode_map[i];
+ if (pmic_mode->id == mode)
+ break;
+ }
+ if (pmic_mode->id != mode) {
+ printf("Invalid mode %d\n", mode);
+ return -EINVAL;
+ }
if (bypassed)
cmd.data = PMIC4_BOB_MODE_PASS;
else
- cmd.data = pmic_mode;
+ cmd.data = pmic_mode->id;
return rpmh_regulator_send_request(vreg, &cmd, true);
}
-static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev,
- unsigned int mode)
+static int rpmh_regulator_vrm_set_mode(struct udevice *rdev,
+ int mode)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
int ret;
+ debug("%s: set_mode %d (current %d)\n", rdev->name, mode, vreg->mode);
+
if (mode == vreg->mode)
return 0;
ret = rpmh_regulator_vrm_set_mode_bypass(vreg, mode, vreg->bypassed);
@@ -331,51 +339,59 @@ static int rpmh_regulator_vrm_set_mode(struct regulator_dev *rdev,
return ret;
}
-static unsigned int rpmh_regulator_vrm_get_mode(struct regulator_dev *rdev)
+static int rpmh_regulator_vrm_get_mode(struct udevice *rdev)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ struct rpmh_vreg *vreg = dev_get_priv(rdev);
+
+ debug("%s: get_mode %d\n", rdev->name, vreg->mode);
return vreg->mode;
}
+static const struct dm_regulator_ops rpmh_regulator_vrm_drms_ops = {
+ .get_value = rpmh_regulator_vrm_get_value,
+ .set_value = rpmh_regulator_vrm_set_value,
+ .set_enable = rpmh_regulator_set_enable_state,
+ .get_enable = rpmh_regulator_is_enabled,
+ .set_mode = rpmh_regulator_vrm_set_mode,
+ .get_mode = rpmh_regulator_vrm_get_mode,
+};
-static const struct regulator_ops rpmh_regulator_vrm_drms_ops = {
- .enable = rpmh_regulator_enable,
- .disable = rpmh_regulator_disable,
- .is_enabled = rpmh_regulator_is_enabled,
- .set_voltage_sel = rpmh_regulator_vrm_set_voltage_sel,
- .get_voltage_sel = rpmh_regulator_vrm_get_voltage_sel,
- .list_voltage = regulator_list_voltage_linear_range,
- .set_mode = rpmh_regulator_vrm_set_mode,
- .get_mode = rpmh_regulator_vrm_get_mode,
- .get_optimum_mode = rpmh_regulator_vrm_get_optimum_mode,
+static struct dm_regulator_mode pmic_mode_map_pmic5_ldo[] = {
+ {
+ .id = REGULATOR_MODE_RETENTION,
+ .register_value = PMIC5_LDO_MODE_RETENTION,
+ .name = "PMIC5_LDO_MODE_RETENTION"
+ }, {
+ .id = REGULATOR_MODE_LPM,
+ .register_value = PMIC5_LDO_MODE_LPM,
+ .name = "PMIC5_LDO_MODE_LPM"
+ }, {
+ .id = REGULATOR_MODE_HPM,
+ .register_value = PMIC5_LDO_MODE_HPM,
+ .name = "PMIC5_LDO_MODE_HPM"
+ },
};
static const struct rpmh_vreg_hw_data pmic5_pldo = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
- },
- .n_linear_ranges = 1,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000),
.n_voltages = 256,
.hpm_min_load_uA = 10000,
.pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+ .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
static const struct rpmh_vreg_hw_data pmic5_pldo_lv = {
.regulator_type = VRM,
.ops = &rpmh_regulator_vrm_drms_ops,
- .voltage_ranges = (struct linear_range[]) {
- REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
- },
- .n_linear_ranges = 1,
+ .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000),
.n_voltages = 63,
.hpm_min_load_uA = 10000,
.pmic_mode_map = pmic_mode_map_pmic5_ldo,
- .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode,
+ .n_modes = ARRAY_SIZE(pmic_mode_map_pmic5_ldo),
};
#define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \
{ \
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 22/24] power: regulator: qcom-rpmh-regulator: adjust probe for U-Boot
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (20 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 21/24] power: regulator: qcom-rpmh-regulator: port ops to U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 10:08 ` [PATCH v6 23/24] power: regulator: qcom-rpmh-regulator: add build infra Caleb Connolly
` (2 subsequent siblings)
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Refactor initialization to use U-Boot's driver model and API.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/qcom-rpmh-regulator.c | 136 +++++++++++++++++++-------
1 file changed, 102 insertions(+), 34 deletions(-)
diff --git a/drivers/power/regulator/qcom-rpmh-regulator.c b/drivers/power/regulator/qcom-rpmh-regulator.c
index b716b380c148..06fd3f31956f 100644
--- a/drivers/power/regulator/qcom-rpmh-regulator.c
+++ b/drivers/power/regulator/qcom-rpmh-regulator.c
@@ -411,66 +411,134 @@ static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = {
RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"),
{}
};
-static int rpmh_regulator_probe(struct platform_device *pdev)
+/* probe an individual regulator */
+static int rpmh_regulator_probe(struct udevice *dev)
{
- struct device *dev = &pdev->dev;
- const struct rpmh_vreg_init_data *vreg_data;
- struct device_node *node;
- struct rpmh_vreg *vreg;
- const char *pmic_id;
- int ret;
+ const struct rpmh_vreg_init_data *init_data;
+ struct rpmh_vreg *priv;
+ struct dm_regulator_uclass_plat *plat_data;
- vreg_data = of_device_get_match_data(dev);
- if (!vreg_data)
+ init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev);
+ priv = dev_get_priv(dev);
+ plat_data = dev_get_uclass_plat(dev);
+
+ priv->dev = dev;
+ priv->addr = cmd_db_read_addr(dev->name);
+ if (!priv->addr) {
+ dev_err(dev, "Failed to read RPMh address for %s\n", dev->name);
return -ENODEV;
-
- ret = of_property_read_string(dev->of_node, "qcom,pmic-id", &pmic_id);
- if (ret < 0) {
- dev_err(dev, "qcom,pmic-id missing in DT node\n");
- return ret;
}
- for_each_available_child_of_node(dev->of_node, node) {
- vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
- if (!vreg) {
- of_node_put(node);
+ priv->hw_data = init_data->hw_data;
+ priv->enabled = -EINVAL;
+ priv->uv = -ENOTRECOVERABLE;
+ if (ofnode_read_u32(dev_ofnode(dev), "regulator-initial-mode", &priv->mode))
+ priv->mode = -EINVAL;
+
+ plat_data->mode = priv->hw_data->pmic_mode_map;
+ plat_data->mode_count = priv->hw_data->n_modes;
+
+ return 0;
+}
+
+/* for non-drm, xob, or bypass regulators add additional driver definitions */
+U_BOOT_DRIVER(rpmh_regulator_drm) = {
+ .name = "rpmh_regulator_drm",
+ .id = UCLASS_REGULATOR,
+ .probe = rpmh_regulator_probe,
+ .priv_auto = sizeof(struct rpmh_vreg),
+ .ops = &rpmh_regulator_vrm_drms_ops,
+};
+
+/* This driver intentionally only supports a subset of the available regulators.
+ * This function checks to see if a given regulator node in DT matches a regulator
+ * defined in the driver.
+ */
+static const struct rpmh_vreg_init_data *
+vreg_get_init_data(const struct rpmh_vreg_init_data *init_data, ofnode node)
+{
+ const struct rpmh_vreg_init_data *data;
+
+ for (data = init_data; data->name; data++) {
+ if (!strcmp(data->name, ofnode_get_name(node)))
+ return data;
+ }
+
+ return NULL;
+}
+
+static int rpmh_regulators_bind(struct udevice *dev)
+{
+ const struct rpmh_vreg_init_data *init_data, *data;
+ const char *pmic_id;
+ char *name;
+ struct driver *drv;
+ ofnode node;
+ int ret;
+ size_t namelen;
+
+ init_data = (const struct rpmh_vreg_init_data *)dev_get_driver_data(dev);
+ if (!init_data) {
+ dev_err(dev, "No RPMh regulator init data\n");
+ return -ENODEV;
+ }
+
+ pmic_id = ofnode_read_string(dev_ofnode(dev), "qcom,pmic-id");
+ if (!pmic_id) {
+ dev_err(dev, "No PMIC ID\n");
+ return -ENODEV;
+ }
+
+ drv = lists_driver_lookup_name("rpmh_regulator_drm");
+
+ ofnode_for_each_subnode(node, dev_ofnode(dev)) {
+ data = vreg_get_init_data(init_data, node);
+ if (!data)
+ continue;
+
+ /* %s is replaced with pmic_id, so subtract 2, then add 1 for the null terminator */
+ namelen = strlen(data->resource_name) + strlen(pmic_id) - 1;
+ name = devm_kzalloc(dev, namelen, GFP_KERNEL);
+ ret = snprintf(name, namelen, data->resource_name, pmic_id);
+ if (ret < 0 || ret >= namelen) {
+ dev_err(dev, "Failed to create RPMh regulator name\n");
return -ENOMEM;
}
- ret = rpmh_regulator_init_vreg(vreg, dev, node, pmic_id,
- vreg_data);
+ ret = device_bind_with_driver_data(dev, drv, name, (ulong)data,
+ node, NULL);
if (ret < 0) {
- of_node_put(node);
+ dev_err(dev, "Failed to bind RPMh regulator %s: %d\n", name, ret);
return ret;
}
}
return 0;
}
-static const struct of_device_id __maybe_unused rpmh_regulator_match_table[] = {
+static const struct udevice_id rpmh_regulator_ids[] = {
{
.compatible = "qcom,pm8150-rpmh-regulators",
- .data = pm8150_vreg_data,
+ .data = (ulong)pm8150_vreg_data,
},
{
.compatible = "qcom,pm8150l-rpmh-regulators",
- .data = pm8150l_vreg_data,
+ .data = (ulong)pm8150l_vreg_data,
},
- {}
+ { /* sentinal */ },
};
-MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table);
-static struct platform_driver rpmh_regulator_driver = {
- .driver = {
- .name = "qcom-rpmh-regulator",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- .of_match_table = of_match_ptr(rpmh_regulator_match_table),
- },
- .probe = rpmh_regulator_probe,
+/* Driver for a 'bank' of regulators. This creates devices for each
+ * individual regulator
+ */
+U_BOOT_DRIVER(rpmh_regulators) = {
+ .name = "rpmh_regulators",
+ .id = UCLASS_MISC,
+ .bind = rpmh_regulators_bind,
+ .of_match = rpmh_regulator_ids,
+ .ops = &rpmh_regulator_vrm_drms_ops,
};
-module_platform_driver(rpmh_regulator_driver);
MODULE_DESCRIPTION("Qualcomm RPMh regulator driver");
MODULE_LICENSE("GPL v2");
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* [PATCH v6 23/24] power: regulator: qcom-rpmh-regulator: add build infra
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (21 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 22/24] power: regulator: qcom-rpmh-regulator: adjust probe for U-Boot Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-15 12:29 ` Neil Armstrong
2024-07-15 10:08 ` [PATCH v6 24/24] qcom_defconfig: enable rpmh regulators Caleb Connolly
2024-07-25 23:38 ` [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
24 siblings, 1 reply; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Add Kconfig and Makefile entries for this driver now that it can build
for U-Boot.
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
drivers/power/regulator/Kconfig | 8 ++++++++
drivers/power/regulator/Makefile | 1 +
2 files changed, 9 insertions(+)
diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
index 102ec7bc5f89..bc061c20d75e 100644
--- a/drivers/power/regulator/Kconfig
+++ b/drivers/power/regulator/Kconfig
@@ -215,8 +215,16 @@ config DM_REGULATOR_GPIO
This config enables implementation of driver-model regulator uclass
features for gpio regulators. The driver implements get/set for
voltage value.
+config DM_REGULATOR_QCOM_RPMH
+ bool "Enable driver model for Qualcomm RPMh regulator"
+ depends on DM_REGULATOR && QCOM_RPMH
+ ---help---
+ Enable support for the Qualcomm RPMh regulator. The driver
+ implements get/set api for a limited set of regulators used
+ by u-boot.
+
config SPL_DM_REGULATOR_GPIO
bool "Enable Driver Model for GPIO REGULATOR in SPL"
depends on DM_REGULATOR_GPIO && SPL_GPIO
select SPL_DM_REGULATOR_COMMON
diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
index f79932d83307..56a527612b74 100644
--- a/drivers/power/regulator/Makefile
+++ b/drivers/power/regulator/Makefile
@@ -20,8 +20,9 @@ obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
+obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
obj-$(CONFIG_$(SPL_TPL_)REGULATOR_RK8XX) += rk8xx.o
obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v6 23/24] power: regulator: qcom-rpmh-regulator: add build infra
2024-07-15 10:08 ` [PATCH v6 23/24] power: regulator: qcom-rpmh-regulator: add build infra Caleb Connolly
@ 2024-07-15 12:29 ` Neil Armstrong
0 siblings, 0 replies; 36+ messages in thread
From: Neil Armstrong @ 2024-07-15 12:29 UTC (permalink / raw)
To: Caleb Connolly, Tom Rini, Sumit Garg, Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
On 15/07/2024 12:08, Caleb Connolly wrote:
> Add Kconfig and Makefile entries for this driver now that it can build
> for U-Boot.
>
> Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
> ---
> drivers/power/regulator/Kconfig | 8 ++++++++
> drivers/power/regulator/Makefile | 1 +
> 2 files changed, 9 insertions(+)
>
> diff --git a/drivers/power/regulator/Kconfig b/drivers/power/regulator/Kconfig
> index 102ec7bc5f89..bc061c20d75e 100644
> --- a/drivers/power/regulator/Kconfig
> +++ b/drivers/power/regulator/Kconfig
> @@ -215,8 +215,16 @@ config DM_REGULATOR_GPIO
> This config enables implementation of driver-model regulator uclass
> features for gpio regulators. The driver implements get/set for
> voltage value.
>
> +config DM_REGULATOR_QCOM_RPMH
> + bool "Enable driver model for Qualcomm RPMh regulator"
> + depends on DM_REGULATOR && QCOM_RPMH
> + ---help---
> + Enable support for the Qualcomm RPMh regulator. The driver
> + implements get/set api for a limited set of regulators used
> + by u-boot.
> +
> config SPL_DM_REGULATOR_GPIO
> bool "Enable Driver Model for GPIO REGULATOR in SPL"
> depends on DM_REGULATOR_GPIO && SPL_GPIO
> select SPL_DM_REGULATOR_COMMON
> diff --git a/drivers/power/regulator/Makefile b/drivers/power/regulator/Makefile
> index f79932d83307..56a527612b74 100644
> --- a/drivers/power/regulator/Makefile
> +++ b/drivers/power/regulator/Makefile
> @@ -20,8 +20,9 @@ obj-$(CONFIG_$(SPL_)REGULATOR_PWM) += pwm_regulator.o
> obj-$(CONFIG_$(SPL_)DM_REGULATOR_FAN53555) += fan53555.o
> obj-$(CONFIG_$(SPL_)DM_REGULATOR_COMMON) += regulator_common.o
> obj-$(CONFIG_$(SPL_)DM_REGULATOR_FIXED) += fixed.o
> obj-$(CONFIG_$(SPL_)DM_REGULATOR_GPIO) += gpio-regulator.o
> +obj-$(CONFIG_DM_REGULATOR_QCOM_RPMH) += qcom-rpmh-regulator.o
> obj-$(CONFIG_$(SPL_TPL_)REGULATOR_RK8XX) += rk8xx.o
> obj-$(CONFIG_DM_REGULATOR_S2MPS11) += s2mps11_regulator.o
> obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
> obj-$(CONFIG_DM_REGULATOR_SANDBOX) += sandbox.o
>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v6 24/24] qcom_defconfig: enable rpmh regulators
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (22 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 23/24] power: regulator: qcom-rpmh-regulator: add build infra Caleb Connolly
@ 2024-07-15 10:08 ` Caleb Connolly
2024-07-25 23:38 ` [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-15 10:08 UTC (permalink / raw)
To: Tom Rini, Caleb Connolly, Neil Armstrong, Sumit Garg,
Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
Enable RPMh, cmd-db, and RPMh regulators. Additionally enable
CMD_REGULATOR for debugging.
Acked-by: Sumit Garg <sumit.garg@linaro.org>
Signed-off-by: Caleb Connolly <caleb.connolly@linaro.org>
---
configs/qcom_defconfig | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/configs/qcom_defconfig b/configs/qcom_defconfig
index ac5ffe772ade..1cbad9db72eb 100644
--- a/configs/qcom_defconfig
+++ b/configs/qcom_defconfig
@@ -35,8 +35,9 @@ CONFIG_CMD_UFS=y
CONFIG_CMD_USB=y
CONFIG_CMD_CAT=y
CONFIG_CMD_BMP=y
CONFIG_CMD_EFIDEBUG=y
+CONFIG_CMD_REGULATOR=y
CONFIG_CMD_LOG=y
CONFIG_OF_LIVE=y
CONFIG_BUTTON_QCOM_PMIC=y
CONFIG_CLK=y
@@ -90,11 +91,15 @@ CONFIG_PINCTRL_QCOM_SM8650=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_QCOM=y
CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_DM_REGULATOR_QCOM_RPMH=y
CONFIG_SCSI=y
CONFIG_MSM_SERIAL=y
CONFIG_MSM_GENI_SERIAL=y
+CONFIG_SOC_QCOM=y
+CONFIG_QCOM_COMMAND_DB=y
+CONFIG_QCOM_RPMH=y
CONFIG_SPMI_MSM=y
CONFIG_SYSINFO=y
CONFIG_SYSINFO_SMBIOS=y
CONFIG_USB=y
--
2.45.2
^ permalink raw reply related [flat|nested] 36+ messages in thread* Re: [PATCH v6 00/24] qcom: rpmh core and regulator support
2024-07-15 10:07 [PATCH v6 00/24] qcom: rpmh core and regulator support Caleb Connolly
` (23 preceding siblings ...)
2024-07-15 10:08 ` [PATCH v6 24/24] qcom_defconfig: enable rpmh regulators Caleb Connolly
@ 2024-07-25 23:38 ` Caleb Connolly
24 siblings, 0 replies; 36+ messages in thread
From: Caleb Connolly @ 2024-07-25 23:38 UTC (permalink / raw)
To: Tom Rini, Neil Armstrong, Sumit Garg, Jaehoon Chung, Simon Glass
Cc: u-boot, u-boot-qcom
On 15/07/2024 12:07, Caleb Connolly wrote:
> This series introduces support for the RPMh (Resource Power Manager
> (hardened)) co-processor and associated regulator driver found on most
> modern Qualcomm platforms (since ~2017).
>
Applied in 1fbd0582a28d108c77d7f9135a7f2c3da2398b72
https://source.denx.de/u-boot/custodians/u-boot-snapdragon/-/tree/qcom-main
> ---
> Caleb Connolly (24):
> dm: core: scan reserved-memory nodes
> linux/bitmap.h: add bitmap_empty helper
> soc: qcom: import rpmh and cmd-db drivers from Linux
> soc: qcom: cmd-db: adjust headers for U-Boot
> soc: qcom: cmd-db: drop unused functions
> soc: qcom: cmd-db: adjust probe for U-Boot
> soc: qcom: cmd-db: adjust for U-Boot API
> soc: qcom: rpmh-rsc: drop unused multi-threading and non-active TCS support
> soc: qcom: rpmh-rsc: adjust headers for U-Boot
> soc: qcom: rpmh-rsc: adjust probe for U-Boot
> soc: qcom: rpmh-rsc: remaining U-Boot API changes
> soc: qcom: rpmh: adjust headers for U-Boot
> soc: qcom: rpmh: drop unused functions
> soc: qcom: rpmh: U-Boot API changes
> soc: qcom: add build infrastructure
> power: regulator: import qcom-rpmh-regulator from Linux
> power: regulator: qcom-rpmh-regulator: adjust headers for U-Boot
> power: regulator: qcom-rpmh-regulator: port over lineage_range helpers
> power: regulator: qcom-rpmh-regulator: adjust structs for U-Boot
> power: regulator: qcom-rpmh-regulator: remove unused regulators
> power: regulator: qcom-rpmh-regulator: port ops to U-Boot
> power: regulator: qcom-rpmh-regulator: adjust probe for U-Boot
> power: regulator: qcom-rpmh-regulator: add build infra
> qcom_defconfig: enable rpmh regulators
>
> configs/qcom_defconfig | 5 +
> drivers/core/root.c | 3 +-
> drivers/power/regulator/Kconfig | 8 +
> drivers/power/regulator/Makefile | 1 +
> drivers/power/regulator/qcom-rpmh-regulator.c | 544 ++++++++++++++++++++++++++
> drivers/soc/Kconfig | 1 +
> drivers/soc/Makefile | 1 +
> drivers/soc/qcom/Kconfig | 27 ++
> drivers/soc/qcom/Makefile | 4 +
> drivers/soc/qcom/cmd-db.c | 225 +++++++++++
> drivers/soc/qcom/rpmh-internal.h | 138 +++++++
> drivers/soc/qcom/rpmh-rsc.c | 505 ++++++++++++++++++++++++
> drivers/soc/qcom/rpmh.c | 110 ++++++
> include/linux/bitmap.h | 8 +
> include/soc/qcom/cmd-db.h | 30 ++
> include/soc/qcom/rpmh.h | 28 ++
> include/soc/qcom/tcs.h | 81 ++++
> 17 files changed, 1718 insertions(+), 1 deletion(-)
> ---
> change-id: 20240611-b4-qcom-rpmh-fcfd32ac2940
> base-commit: 834df20b4ef50cda26936fbc435689fa0c5d47b1
>
> // Caleb (they/them)
>
--
// Caleb (they/them)
^ permalink raw reply [flat|nested] 36+ messages in thread