blob: 8d6abe13dbc6d3ccf0e500efb24674214a0ab99b [file] [log] [blame]
Andreas Dannenberg24c6e912018-08-27 15:57:45 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Texas Instruments System Control Interface (TI SCI) power domain driver
4 *
Nishanth Menoneaa39c62023-11-01 15:56:03 -05005 * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
Andreas Dannenberg24c6e912018-08-27 15:57:45 +05306 * Andreas Dannenberg <dannenberg@ti.com>
7 *
8 * Loosely based on Linux kernel ti_sci_pm_domains.c...
9 */
10
11#include <common.h>
12#include <dm.h>
13#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070015#include <malloc.h>
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053016#include <power-domain-uclass.h>
Simon Glass9bc15642020-02-03 07:36:16 -070017#include <dm/device_compat.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053019#include <linux/soc/ti/ti_sci_protocol.h>
Lokesh Vutlae34f7a82019-06-07 19:24:46 +053020#include <dt-bindings/soc/ti,sci_pm_domain.h>
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053021
22/**
23 * struct ti_sci_power_domain_data - pm domain controller information structure
24 * @sci: TI SCI handle used for communication with system controller
25 */
26struct ti_sci_power_domain_data {
27 const struct ti_sci_handle *sci;
28};
29
30static int ti_sci_power_domain_probe(struct udevice *dev)
31{
32 struct ti_sci_power_domain_data *data = dev_get_priv(dev);
33
34 debug("%s(dev=%p)\n", __func__, dev);
35
36 if (!data)
37 return -ENOMEM;
38
39 /* Store handle for communication with the system controller */
40 data->sci = ti_sci_get_handle(dev);
41 if (IS_ERR(data->sci))
42 return PTR_ERR(data->sci);
43
44 return 0;
45}
46
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053047static int ti_sci_power_domain_on(struct power_domain *pd)
48{
49 struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
50 const struct ti_sci_handle *sci = data->sci;
51 const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
Lokesh Vutlae34f7a82019-06-07 19:24:46 +053052 u8 flags = (uintptr_t)pd->priv;
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053053 int ret;
54
55 debug("%s(pd=%p)\n", __func__, pd);
56
Lokesh Vutlae34f7a82019-06-07 19:24:46 +053057 if (flags & TI_SCI_PD_EXCLUSIVE)
58 ret = dops->get_device_exclusive(sci, pd->id);
59 else
60 ret = dops->get_device(sci, pd->id);
61
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053062 if (ret)
Nishanth Menon0401fb62019-08-01 19:08:24 +053063 dev_err(pd->dev, "%s: get_device(%lu) failed (%d)\n",
64 __func__, pd->id, ret);
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053065
66 return ret;
67}
68
69static int ti_sci_power_domain_off(struct power_domain *pd)
70{
71 struct ti_sci_power_domain_data *data = dev_get_priv(pd->dev);
72 const struct ti_sci_handle *sci = data->sci;
73 const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops;
74 int ret;
75
76 debug("%s(pd=%p)\n", __func__, pd);
77
78 ret = dops->put_device(sci, pd->id);
79 if (ret)
Nishanth Menon0401fb62019-08-01 19:08:24 +053080 dev_err(pd->dev, "%s: put_device(%lu) failed (%d)\n",
81 __func__, pd->id, ret);
Andreas Dannenberg24c6e912018-08-27 15:57:45 +053082
83 return ret;
84}
85
Lokesh Vutlae34f7a82019-06-07 19:24:46 +053086static int ti_sci_power_domain_of_xlate(struct power_domain *pd,
87 struct ofnode_phandle_args *args)
88{
89 u8 flags;
90
91 debug("%s(power_domain=%p)\n", __func__, pd);
92
93 if (args->args_count < 1) {
94 debug("Invalid args_count: %d\n", args->args_count);
95 return -EINVAL;
96 }
97
98 pd->id = args->args[0];
99 /* By default request for device exclusive */
100 flags = TI_SCI_PD_EXCLUSIVE;
101 if (args->args_count == 2)
102 flags = args->args[1] & TI_SCI_PD_EXCLUSIVE;
103 pd->priv = (void *)(uintptr_t)flags;
104
105 return 0;
106}
107
Andreas Dannenberg24c6e912018-08-27 15:57:45 +0530108static const struct udevice_id ti_sci_power_domain_of_match[] = {
109 { .compatible = "ti,sci-pm-domain" },
110 { /* sentinel */ }
111};
112
113static struct power_domain_ops ti_sci_power_domain_ops = {
Andreas Dannenberg24c6e912018-08-27 15:57:45 +0530114 .on = ti_sci_power_domain_on,
115 .off = ti_sci_power_domain_off,
Lokesh Vutlae34f7a82019-06-07 19:24:46 +0530116 .of_xlate = ti_sci_power_domain_of_xlate,
Andreas Dannenberg24c6e912018-08-27 15:57:45 +0530117};
118
119U_BOOT_DRIVER(ti_sci_pm_domains) = {
120 .name = "ti-sci-pm-domains",
121 .id = UCLASS_POWER_DOMAIN,
122 .of_match = ti_sci_power_domain_of_match,
123 .probe = ti_sci_power_domain_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700124 .priv_auto = sizeof(struct ti_sci_power_domain_data),
Andreas Dannenberg24c6e912018-08-27 15:57:45 +0530125 .ops = &ti_sci_power_domain_ops,
126};