From: Tero Kristo <kristo@kernel.org>
To: lokeshvutla@ti.com, trini@konsulko.com, u-boot@lists.denx.de
Subject: [PATCHv6 14/26] power: domain: Introduce driver for raw TI K3 PDs
Date: Fri, 11 Jun 2021 11:45:15 +0300 [thread overview]
Message-ID: <20210611084527.7048-15-kristo@kernel.org> (raw)
In-Reply-To: <20210611084527.7048-1-kristo@kernel.org>
From: Tero Kristo <t-kristo@ti.com>
Normally, power domains are handled via TI-SCI in K3 SoCs. However,
SPL is not going to have access to sysfw resources, so it must control
them directly. Add driver for supporting this.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Signed-off-by: Tero Kristo <kristo@kernel.org>
Reviewed-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/power/domain/Kconfig | 7 +
drivers/power/domain/Makefile | 1 +
drivers/power/domain/ti-power-domain.c | 368 +++++++++++++++++++++++++
include/k3-dev.h | 76 +++++
4 files changed, 452 insertions(+)
create mode 100644 drivers/power/domain/ti-power-domain.c
create mode 100644 include/k3-dev.h
diff --git a/drivers/power/domain/Kconfig b/drivers/power/domain/Kconfig
index a0fd980752..99b3f9ae71 100644
--- a/drivers/power/domain/Kconfig
+++ b/drivers/power/domain/Kconfig
@@ -72,4 +72,11 @@ config TI_SCI_POWER_DOMAIN
help
Generic power domain implementation for TI devices implementing the
TI SCI protocol.
+
+config TI_POWER_DOMAIN
+ bool "Enable the TI K3 Power domain driver"
+ depends on POWER_DOMAIN && ARCH_K3
+ help
+ Generic power domain implementation for TI K3 devices.
+
endmenu
diff --git a/drivers/power/domain/Makefile b/drivers/power/domain/Makefile
index 45bf9f6383..3d1e5f073c 100644
--- a/drivers/power/domain/Makefile
+++ b/drivers/power/domain/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain.o
obj-$(CONFIG_SANDBOX_POWER_DOMAIN) += sandbox-power-domain-test.o
obj-$(CONFIG_TEGRA186_POWER_DOMAIN) += tegra186-power-domain.o
obj-$(CONFIG_TI_SCI_POWER_DOMAIN) += ti-sci-power-domain.o
+obj-$(CONFIG_TI_POWER_DOMAIN) += ti-power-domain.o
diff --git a/drivers/power/domain/ti-power-domain.c b/drivers/power/domain/ti-power-domain.c
new file mode 100644
index 0000000000..56bc6fc31c
--- /dev/null
+++ b/drivers/power/domain/ti-power-domain.c
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments power domain driver
+ *
+ * Copyright (C) 2020-2021 Texas Instruments Incorporated - http://www.ti.com/
+ * Tero Kristo <t-kristo@ti.com>
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <power-domain-uclass.h>
+#include <soc.h>
+#include <k3-dev.h>
+#include <linux/iopoll.h>
+
+#define PSC_PTCMD 0x120
+#define PSC_PTSTAT 0x128
+#define PSC_PDSTAT 0x200
+#define PSC_PDCTL 0x300
+#define PSC_MDSTAT 0x800
+#define PSC_MDCTL 0xa00
+
+#define PDCTL_STATE_MASK 0x1
+#define PDCTL_STATE_OFF 0x0
+#define PDCTL_STATE_ON 0x1
+
+#define MDSTAT_STATE_MASK 0x3f
+#define MDSTAT_BUSY_MASK 0x30
+#define MDSTAT_STATE_SWRSTDISABLE 0x0
+#define MDSTAT_STATE_ENABLE 0x3
+
+#define LPSC_TIMEOUT 1000
+#define PD_TIMEOUT 1000
+
+static u32 psc_read(struct ti_psc *psc, u32 reg)
+{
+ u32 val;
+
+ val = readl(psc->base + reg);
+ debug("%s: 0x%x from %p\n", __func__, val, psc->base + reg);
+ return val;
+}
+
+static void psc_write(u32 val, struct ti_psc *psc, u32 reg)
+{
+ debug("%s: 0x%x to %p\n", __func__, val, psc->base + reg);
+ writel(val, psc->base + reg);
+}
+
+static u32 pd_read(struct ti_pd *pd, u32 reg)
+{
+ return psc_read(pd->psc, reg + 4 * pd->id);
+}
+
+static void pd_write(u32 val, struct ti_pd *pd, u32 reg)
+{
+ psc_write(val, pd->psc, reg + 4 * pd->id);
+}
+
+static u32 lpsc_read(struct ti_lpsc *lpsc, u32 reg)
+{
+ return psc_read(lpsc->psc, reg + 4 * lpsc->id);
+}
+
+static void lpsc_write(u32 val, struct ti_lpsc *lpsc, u32 reg)
+{
+ psc_write(val, lpsc->psc, reg + 4 * lpsc->id);
+}
+
+static const struct soc_attr ti_k3_soc_pd_data[] = {
+#if IS_ENABLED(CONFIG_SOC_K3_J721E)
+ {
+ .family = "J721E",
+ .data = &j721e_pd_platdata,
+ },
+ {
+ .family = "J7200",
+ .data = &j7200_pd_platdata,
+ },
+#endif
+ { /* sentinel */ }
+};
+
+static int ti_power_domain_probe(struct udevice *dev)
+{
+ struct ti_k3_pd_platdata *data = dev_get_priv(dev);
+ const struct soc_attr *soc_match_data;
+ const struct ti_k3_pd_platdata *pdata;
+
+ printf("%s(dev=%p)\n", __func__, dev);
+
+ if (!data)
+ return -ENOMEM;
+
+ soc_match_data = soc_device_match(ti_k3_soc_pd_data);
+ if (!soc_match_data)
+ return -ENODEV;
+
+ pdata = (const struct ti_k3_pd_platdata *)soc_match_data->data;
+
+ data->psc = pdata->psc;
+ data->pd = pdata->pd;
+ data->lpsc = pdata->lpsc;
+ data->devs = pdata->devs;
+ data->num_psc = pdata->num_psc;
+ data->num_pd = pdata->num_pd;
+ data->num_lpsc = pdata->num_lpsc;
+ data->num_devs = pdata->num_devs;
+
+ return 0;
+}
+
+static int ti_pd_wait(struct ti_pd *pd)
+{
+ u32 ptstat;
+ int ret;
+
+ ret = readl_poll_timeout(pd->psc->base + PSC_PTSTAT, ptstat,
+ !(ptstat & BIT(pd->id)), PD_TIMEOUT);
+
+ if (ret)
+ printf("%s: psc%d, pd%d failed to transition.\n", __func__,
+ pd->psc->id, pd->id);
+
+ return ret;
+}
+
+static void ti_pd_transition(struct ti_pd *pd)
+{
+ psc_write(BIT(pd->id), pd->psc, PSC_PTCMD);
+}
+
+static u8 ti_pd_state(struct ti_pd *pd)
+{
+ return pd_read(pd, PSC_PDCTL) & PDCTL_STATE_MASK;
+}
+
+static int ti_pd_get(struct ti_pd *pd)
+{
+ u32 pdctl;
+ int ret;
+
+ pd->usecount++;
+
+ if (pd->usecount > 1)
+ return 0;
+
+ if (pd->depend) {
+ ret = ti_pd_get(pd->depend);
+ if (ret)
+ return ret;
+ ti_pd_transition(pd->depend);
+ ret = ti_pd_wait(pd->depend);
+ if (ret)
+ return ret;
+ }
+
+ pdctl = pd_read(pd, PSC_PDCTL);
+
+ if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_ON)
+ return 0;
+
+ debug("%s: enabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
+
+ pdctl &= ~PDCTL_STATE_MASK;
+ pdctl |= PDCTL_STATE_ON;
+
+ pd_write(pdctl, pd, PSC_PDCTL);
+
+ return 0;
+}
+
+static int ti_pd_put(struct ti_pd *pd)
+{
+ u32 pdctl;
+ int ret;
+
+ pd->usecount--;
+
+ if (pd->usecount > 0)
+ return 0;
+
+ pdctl = pd_read(pd, PSC_PDCTL);
+ if ((pdctl & PDCTL_STATE_MASK) == PDCTL_STATE_OFF)
+ return 0;
+
+ pdctl &= ~PDCTL_STATE_MASK;
+ pdctl |= PDCTL_STATE_OFF;
+
+ debug("%s: disabling psc:%d, pd:%d\n", __func__, pd->psc->id, pd->id);
+
+ pd_write(pdctl, pd, PSC_PDCTL);
+
+ if (pd->depend) {
+ ti_pd_transition(pd);
+ ret = ti_pd_wait(pd);
+ if (ret)
+ return ret;
+
+ ret = ti_pd_put(pd->depend);
+ if (ret)
+ return ret;
+ ti_pd_transition(pd->depend);
+ ret = ti_pd_wait(pd->depend);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ti_lpsc_wait(struct ti_lpsc *lpsc)
+{
+ u32 mdstat;
+ int ret;
+
+ ret = readl_poll_timeout(lpsc->psc->base + PSC_MDSTAT + lpsc->id * 4,
+ mdstat,
+ !(mdstat & MDSTAT_BUSY_MASK), LPSC_TIMEOUT);
+
+ if (ret)
+ printf("%s: module %d failed to transition.\n", __func__,
+ lpsc->id);
+
+ return ret;
+}
+
+static u8 lpsc_get_state(struct ti_lpsc *lpsc)
+{
+ return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
+}
+
+static int ti_lpsc_transition(struct ti_lpsc *lpsc, u8 state)
+{
+ struct ti_pd *psc_pd;
+ int ret;
+ u32 mdctl;
+
+ psc_pd = lpsc->pd;
+
+ if (state == MDSTAT_STATE_ENABLE) {
+ lpsc->usecount++;
+ if (lpsc->usecount > 1)
+ return 0;
+ } else {
+ lpsc->usecount--;
+ if (lpsc->usecount >= 1)
+ return 0;
+ }
+
+ debug("%s: transitioning psc:%d, lpsc:%d to %x\n", __func__,
+ lpsc->psc->id, lpsc->id, state);
+
+ if (lpsc->depend)
+ ti_lpsc_transition(lpsc->depend, state);
+
+ mdctl = lpsc_read(lpsc, PSC_MDCTL);
+ if ((mdctl & MDSTAT_STATE_MASK) == state)
+ return 0;
+
+ if (state == MDSTAT_STATE_ENABLE)
+ ti_pd_get(psc_pd);
+ else
+ ti_pd_put(psc_pd);
+
+ mdctl &= ~MDSTAT_STATE_MASK;
+ mdctl |= state;
+
+ lpsc_write(mdctl, lpsc, PSC_MDCTL);
+
+ ti_pd_transition(psc_pd);
+ ret = ti_pd_wait(psc_pd);
+ if (ret)
+ return ret;
+
+ return ti_lpsc_wait(lpsc);
+}
+
+static int ti_power_domain_transition(struct power_domain *pd, u8 state)
+{
+ struct ti_lpsc *lpsc = pd->priv;
+
+ return ti_lpsc_transition(lpsc, state);
+}
+
+static int ti_power_domain_on(struct power_domain *pd)
+{
+ debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
+
+ return ti_power_domain_transition(pd, MDSTAT_STATE_ENABLE);
+}
+
+static int ti_power_domain_off(struct power_domain *pd)
+{
+ debug("%s(pd=%p, id=%lu)\n", __func__, pd, pd->id);
+
+ return ti_power_domain_transition(pd, MDSTAT_STATE_SWRSTDISABLE);
+}
+
+static struct ti_lpsc *lpsc_lookup(struct ti_k3_pd_platdata *data, int id)
+{
+ int idx;
+
+ for (idx = 0; idx < data->num_devs; idx++)
+ if (data->devs[idx].id == id)
+ return data->devs[idx].lpsc;
+
+ return NULL;
+}
+
+static int ti_power_domain_of_xlate(struct power_domain *pd,
+ struct ofnode_phandle_args *args)
+{
+ struct ti_k3_pd_platdata *data = dev_get_priv(pd->dev);
+ struct ti_lpsc *lpsc;
+
+ debug("%s(power_domain=%p, id=%d)\n", __func__, pd, args->args[0]);
+
+ if (args->args_count < 1) {
+ printf("Invalid args_count: %d\n", args->args_count);
+ return -EINVAL;
+ }
+
+ lpsc = lpsc_lookup(data, args->args[0]);
+ if (!lpsc) {
+ printf("%s: invalid dev-id: %d\n", __func__, args->args[0]);
+ return -ENOENT;
+ }
+
+ pd->id = lpsc->id;
+ pd->priv = lpsc;
+
+ return 0;
+}
+
+static int ti_power_domain_request(struct power_domain *pd)
+{
+ return 0;
+}
+
+static int ti_power_domain_free(struct power_domain *pd)
+{
+ return 0;
+}
+
+static const struct udevice_id ti_power_domain_of_match[] = {
+ { .compatible = "ti,sci-pm-domain" },
+ { /* sentinel */ }
+};
+
+static struct power_domain_ops ti_power_domain_ops = {
+ .on = ti_power_domain_on,
+ .off = ti_power_domain_off,
+ .of_xlate = ti_power_domain_of_xlate,
+ .request = ti_power_domain_request,
+ .rfree = ti_power_domain_free,
+};
+
+U_BOOT_DRIVER(ti_pm_domains) = {
+ .name = "ti-pm-domains",
+ .id = UCLASS_POWER_DOMAIN,
+ .of_match = ti_power_domain_of_match,
+ .probe = ti_power_domain_probe,
+ .priv_auto = sizeof(struct ti_k3_pd_platdata),
+ .ops = &ti_power_domain_ops,
+};
diff --git a/include/k3-dev.h b/include/k3-dev.h
new file mode 100644
index 0000000000..de3a8bdf9e
--- /dev/null
+++ b/include/k3-dev.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Texas Instruments K3 Device Platform Data
+ *
+ * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
+ */
+#ifndef __K3_DEV_H__
+#define __K3_DEV_H__
+
+#include <asm/io.h>
+#include <linux/types.h>
+#include <stdint.h>
+
+#define LPSC_MODULE_EXISTS BIT(0)
+#define LPSC_NO_CLOCK_GATING BIT(1)
+#define LPSC_DEPENDS BIT(2)
+#define LPSC_HAS_RESET_ISO BIT(3)
+#define LPSC_HAS_LOCAL_RESET BIT(4)
+#define LPSC_NO_MODULE_RESET BIT(5)
+
+#define PSC_PD_EXISTS BIT(0)
+#define PSC_PD_ALWAYSON BIT(1)
+#define PSC_PD_DEPENDS BIT(2)
+
+struct ti_psc {
+ int id;
+ void __iomem *base;
+};
+
+struct ti_pd;
+
+struct ti_pd {
+ int id;
+ int usecount;
+ struct ti_psc *psc;
+ struct ti_pd *depend;
+};
+
+struct ti_lpsc;
+
+struct ti_lpsc {
+ int id;
+ int usecount;
+ struct ti_psc *psc;
+ struct ti_pd *pd;
+ struct ti_lpsc *depend;
+};
+
+struct ti_dev {
+ struct ti_lpsc *lpsc;
+ int id;
+};
+
+/**
+ * struct ti_k3_pd_platdata - pm domain controller information structure
+ */
+struct ti_k3_pd_platdata {
+ struct ti_psc *psc;
+ struct ti_pd *pd;
+ struct ti_lpsc *lpsc;
+ struct ti_dev *devs;
+ int num_psc;
+ int num_pd;
+ int num_lpsc;
+ int num_devs;
+};
+
+#define PSC(_id, _base) { .id = _id, .base = (void *)_base, }
+#define PSC_PD(_id, _psc, _depend) { .id = _id, .psc = _psc, .depend = _depend }
+#define PSC_LPSC(_id, _psc, _pd, _depend) { .id = _id, .psc = _psc, .pd = _pd, .depend = _depend }
+#define PSC_DEV(_id, _lpsc) { .id = _id, .lpsc = _lpsc }
+
+extern const struct ti_k3_pd_platdata j721e_pd_platdata;
+extern const struct ti_k3_pd_platdata j7200_pd_platdata;
+
+#endif
--
2.17.1
next prev parent reply other threads:[~2021-06-11 8:48 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-06-11 8:45 [PATCHv6 00/26] HSM rearch series for TI K3 devices Tero Kristo
2021-06-11 8:45 ` [PATCHv6 01/26] lib: rational: copy the rational fraction lib routines from Linux Tero Kristo
2021-06-11 8:45 ` [PATCHv6 02/26] arm: mach-k3: introduce new config option for sysfw split Tero Kristo
2021-06-11 8:45 ` [PATCHv6 03/26] remoteproc: k3-r5: remove sysfw PM calls if not supported Tero Kristo
2021-06-11 8:45 ` [PATCHv6 04/26] common: fit: Update board_fit_image_post_process() to pass fit and node_offset Tero Kristo
2021-06-11 8:45 ` [PATCHv6 05/26] clk: fixed_rate: add API for directly registering fixed rate clocks Tero Kristo
2021-06-11 8:45 ` [PATCHv6 06/26] clk: fix clock tree dump to properly dump out every registered clock Tero Kristo
2021-06-11 8:45 ` [PATCHv6 07/26] clk: do not attempt to fetch clock pointer with null device Tero Kristo
2021-06-11 8:45 ` [PATCHv6 08/26] clk: add support for setting clk rate from cmdline Tero Kristo
2021-06-11 8:45 ` [PATCHv6 09/26] clk: sci-clk: fix return value of set_rate Tero Kristo
2021-06-11 8:45 ` [PATCHv6 10/26] clk: fix assigned-clocks to pass with deferring provider Tero Kristo
2021-06-11 8:45 ` [PATCHv6 11/26] clk: fix set_rate to clean up cached rates for the hierarchy Tero Kristo
2021-06-11 8:45 ` [PATCHv6 12/26] clk: add support for TI K3 SoC PLL Tero Kristo
2021-06-11 8:45 ` [PATCHv6 13/26] clk: add support for TI K3 SoC clocks Tero Kristo
2021-06-11 8:45 ` Tero Kristo [this message]
2021-06-11 8:45 ` [PATCHv6 15/26] cmd: ti: pd: Add debug command for K3 power domains Tero Kristo
2021-06-11 8:45 ` [PATCHv6 16/26] tools: k3_fit_atf: add DM binary to the FIT image Tero Kristo
2021-06-11 8:45 ` [PATCHv6 17/26] arm: mach-k3: Add platform data for j721e and j7200 Tero Kristo
2021-06-11 8:45 ` [PATCHv6 18/26] arm: mach-k3: add support for detecting firmware images from FIT Tero Kristo
2021-06-11 8:45 ` [PATCHv6 19/26] arm: mach-k3: do board config for PM only if supported Tero Kristo
2021-06-11 8:45 ` [PATCHv6 20/26] arm: mach-k3: common: Drop main r5 start Tero Kristo
2021-06-11 8:45 ` [PATCHv6 21/26] arm: mach-k3: sysfw-loader: pass boardcfg to sciserver Tero Kristo
2021-06-11 8:45 ` [PATCHv6 22/26] arm: mach-k3: j721e_init: Force early probe of clk-k3 driver Tero Kristo
2021-06-11 8:45 ` [PATCHv6 23/26] configs: j721e_evm_r5: Enable raw access power management features Tero Kristo
2021-06-11 8:45 ` [PATCHv6 24/26] configs: j7200_evm_r5: " Tero Kristo
2021-06-11 8:45 ` [PATCHv6 25/26] board: ti: j72xx: README: update build instructions and image formats Tero Kristo
2021-06-11 8:45 ` [PATCHv6 26/26] arm: dts: k3-j72xx: correct MCU timer1 frequency Tero Kristo
2021-06-11 11:08 ` [PATCHv6 00/26] HSM rearch series for TI K3 devices Lokesh Vutla
2021-06-11 11:18 ` Tero Kristo
2021-06-11 13:43 ` Lokesh Vutla
2021-06-11 14:13 ` Tom Rini
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210611084527.7048-15-kristo@kernel.org \
--to=kristo@kernel.org \
--cc=lokeshvutla@ti.com \
--cc=trini@konsulko.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.