1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Texas Instruments System Control Interface (TI SCI) reset driver 4 * 5 * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ 6 * Andreas Dannenberg <dannenberg@ti.com> 7 * 8 * Loosely based on Linux kernel reset-ti-sci.c... 9 */ 10 11 #include <common.h> 12 #include <dm.h> 13 #include <errno.h> 14 #include <reset-uclass.h> 15 #include <linux/soc/ti/ti_sci_protocol.h> 16 17 /** 18 * struct ti_sci_reset_data - reset controller information structure 19 * @sci: TI SCI handle used for communication with system controller 20 */ 21 struct ti_sci_reset_data { 22 const struct ti_sci_handle *sci; 23 }; 24 25 static int ti_sci_reset_probe(struct udevice *dev) 26 { 27 struct ti_sci_reset_data *data = dev_get_priv(dev); 28 29 debug("%s(dev=%p)\n", __func__, dev); 30 31 if (!data) 32 return -ENOMEM; 33 34 /* Store handle for communication with the system controller */ 35 data->sci = ti_sci_get_handle(dev); 36 if (IS_ERR(data->sci)) 37 return PTR_ERR(data->sci); 38 39 return 0; 40 } 41 42 static int ti_sci_reset_of_xlate(struct reset_ctl *rst, 43 struct ofnode_phandle_args *args) 44 { 45 debug("%s(rst=%p, args_count=%d)\n", __func__, rst, args->args_count); 46 47 if (args->args_count != 2) { 48 debug("Invalid args_count: %d\n", args->args_count); 49 return -EINVAL; 50 } 51 52 /* 53 * On TI SCI-based devices, the reset provider id field is used as a 54 * device ID, and the data field is used as the associated reset mask. 55 */ 56 rst->id = args->args[0]; 57 rst->data = args->args[1]; 58 59 return 0; 60 } 61 62 static int ti_sci_reset_request(struct reset_ctl *rst) 63 { 64 debug("%s(rst=%p)\n", __func__, rst); 65 return 0; 66 } 67 68 static int ti_sci_reset_free(struct reset_ctl *rst) 69 { 70 debug("%s(rst=%p)\n", __func__, rst); 71 return 0; 72 } 73 74 /** 75 * ti_sci_reset_set() - program a device's reset 76 * @rst: Handle to a single reset signal 77 * @assert: boolean flag to indicate assert or deassert 78 * 79 * This is a common internal function used to assert or deassert a device's 80 * reset using the TI SCI protocol. The device's reset is asserted if the 81 * @assert argument is true, or deasserted if @assert argument is false. 82 * The mechanism itself is a read-modify-write procedure, the current device 83 * reset register is read using a TI SCI device operation, the new value is 84 * set or un-set using the reset's mask, and the new reset value written by 85 * using another TI SCI device operation. 86 * 87 * Return: 0 for successful request, else a corresponding error value 88 */ 89 static int ti_sci_reset_set(struct reset_ctl *rst, bool assert) 90 { 91 struct ti_sci_reset_data *data = dev_get_priv(rst->dev); 92 const struct ti_sci_handle *sci = data->sci; 93 const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops; 94 u32 reset_state; 95 int ret; 96 97 ret = dops->get_device_resets(sci, rst->id, &reset_state); 98 if (ret) { 99 dev_err(rst->dev, "%s: get_device_resets failed (%d)\n", 100 __func__, ret); 101 return ret; 102 } 103 104 if (assert) 105 reset_state |= rst->data; 106 else 107 reset_state &= ~rst->data; 108 109 ret = dops->set_device_resets(sci, rst->id, reset_state); 110 if (ret) { 111 dev_err(rst->dev, "%s: set_device_resets failed (%d)\n", 112 __func__, ret); 113 return ret; 114 } 115 116 return 0; 117 } 118 119 /** 120 * ti_sci_reset_assert() - assert device reset 121 * @rst: Handle to a single reset signal 122 * 123 * This function implements the reset driver op to assert a device's reset 124 * using the TI SCI protocol. This invokes the function ti_sci_reset_set() 125 * with the corresponding parameters as passed in, but with the @assert 126 * argument set to true for asserting the reset. 127 * 128 * Return: 0 for successful request, else a corresponding error value 129 */ 130 static int ti_sci_reset_assert(struct reset_ctl *rst) 131 { 132 debug("%s(rst=%p)\n", __func__, rst); 133 return ti_sci_reset_set(rst, true); 134 } 135 136 /** 137 * ti_sci_reset_deassert() - deassert device reset 138 * @rst: Handle to a single reset signal 139 * 140 * This function implements the reset driver op to deassert a device's reset 141 * using the TI SCI protocol. This invokes the function ti_sci_reset_set() 142 * with the corresponding parameters as passed in, but with the @assert 143 * argument set to false for deasserting the reset. 144 * 145 * Return: 0 for successful request, else a corresponding error value 146 */ 147 static int ti_sci_reset_deassert(struct reset_ctl *rst) 148 { 149 debug("%s(rst=%p)\n", __func__, rst); 150 return ti_sci_reset_set(rst, false); 151 } 152 153 /** 154 * ti_sci_reset_status() - check device reset status 155 * @rst: Handle to a single reset signal 156 * 157 * This function implements the reset driver op to return the status of a 158 * device's reset using the TI SCI protocol. The reset register value is read 159 * by invoking the TI SCI device operation .get_device_resets(), and the 160 * status of the specific reset is extracted and returned using this reset's 161 * reset mask. 162 * 163 * Return: 0 if reset is deasserted, or a non-zero value if reset is asserted 164 */ 165 static int ti_sci_reset_status(struct reset_ctl *rst) 166 { 167 struct ti_sci_reset_data *data = dev_get_priv(rst->dev); 168 const struct ti_sci_handle *sci = data->sci; 169 const struct ti_sci_dev_ops *dops = &sci->ops.dev_ops; 170 u32 reset_state; 171 int ret; 172 173 debug("%s(rst=%p)\n", __func__, rst); 174 175 ret = dops->get_device_resets(sci, rst->id, &reset_state); 176 if (ret) { 177 dev_err(rst->dev, "%s: get_device_resets failed (%d)\n", 178 __func__, ret); 179 return ret; 180 } 181 182 return reset_state & rst->data; 183 } 184 185 static const struct udevice_id ti_sci_reset_of_match[] = { 186 { .compatible = "ti,sci-reset", }, 187 { /* sentinel */ }, 188 }; 189 190 static struct reset_ops ti_sci_reset_ops = { 191 .of_xlate = ti_sci_reset_of_xlate, 192 .request = ti_sci_reset_request, 193 .free = ti_sci_reset_free, 194 .rst_assert = ti_sci_reset_assert, 195 .rst_deassert = ti_sci_reset_deassert, 196 .rst_status = ti_sci_reset_status, 197 }; 198 199 U_BOOT_DRIVER(ti_sci_reset) = { 200 .name = "ti-sci-reset", 201 .id = UCLASS_RESET, 202 .of_match = ti_sci_reset_of_match, 203 .probe = ti_sci_reset_probe, 204 .priv_auto_alloc_size = sizeof(struct ti_sci_reset_data), 205 .ops = &ti_sci_reset_ops, 206 }; 207