123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- // 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);
- }
- 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;
- }
- u8 lpsc_get_state(struct ti_lpsc *lpsc)
- {
- return lpsc_read(lpsc, PSC_MDCTL) & MDSTAT_STATE_MASK;
- }
- 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,
- };
|