blob: 80e8dffdbb187cdaa26c79431002097b0f49ba8b [file] [log] [blame]
Fabien Dessenne6bed04f2019-05-31 15:11:34 +02001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
2/*
3 * Copyright (C) 2019, STMicroelectronics - All Rights Reserved
4 */
5#define pr_fmt(fmt) "%s: " fmt, __func__
6#include <common.h>
7#include <dm.h>
8#include <errno.h>
9#include <fdtdec.h>
10#include <regmap.h>
11#include <remoteproc.h>
12#include <reset.h>
13#include <syscon.h>
14#include <asm/io.h>
Simon Glass61b29b82020-02-03 07:36:15 -070015#include <linux/err.h>
Fabien Dessenne6bed04f2019-05-31 15:11:34 +020016
17#define RCC_GCR_HOLD_BOOT 0
18#define RCC_GCR_RELEASE_BOOT 1
19
20/**
21 * struct stm32_copro_privdata - power processor private data
22 * @reset_ctl: reset controller handle
23 * @hold_boot_regmap: regmap for remote processor reset hold boot
24 * @hold_boot_offset: offset of the register controlling the hold boot setting
25 * @hold_boot_mask: bitmask of the register for the hold boot field
Fabien Dessenne33fd4192019-10-30 14:38:33 +010026 * @rsc_table_addr: resource table address
Fabien Dessenne6bed04f2019-05-31 15:11:34 +020027 */
28struct stm32_copro_privdata {
29 struct reset_ctl reset_ctl;
30 struct regmap *hold_boot_regmap;
31 uint hold_boot_offset;
32 uint hold_boot_mask;
Fabien Dessenne33fd4192019-10-30 14:38:33 +010033 ulong rsc_table_addr;
Fabien Dessenne6bed04f2019-05-31 15:11:34 +020034};
35
36/**
37 * stm32_copro_probe() - Basic probe
38 * @dev: corresponding STM32 remote processor device
39 * @return 0 if all went ok, else corresponding -ve error
40 */
41static int stm32_copro_probe(struct udevice *dev)
42{
43 struct stm32_copro_privdata *priv;
44 struct regmap *regmap;
45 const fdt32_t *cell;
46 int len, ret;
47
48 priv = dev_get_priv(dev);
49
50 regmap = syscon_regmap_lookup_by_phandle(dev, "st,syscfg-holdboot");
51 if (IS_ERR(regmap)) {
52 dev_err(dev, "unable to find holdboot regmap (%ld)\n",
53 PTR_ERR(regmap));
54 return PTR_ERR(regmap);
55 }
56
57 cell = dev_read_prop(dev, "st,syscfg-holdboot", &len);
58 if (len < 3 * sizeof(fdt32_t)) {
59 dev_err(dev, "holdboot offset and mask not available\n");
60 return -EINVAL;
61 }
62
63 priv->hold_boot_regmap = regmap;
64 priv->hold_boot_offset = fdtdec_get_number(cell + 1, 1);
65 priv->hold_boot_mask = fdtdec_get_number(cell + 2, 1);
66
67 ret = reset_get_by_index(dev, 0, &priv->reset_ctl);
68 if (ret) {
69 dev_err(dev, "failed to get reset (%d)\n", ret);
70 return ret;
71 }
72
73 dev_dbg(dev, "probed\n");
74
75 return 0;
76}
77
78/**
79 * stm32_copro_set_hold_boot() - Hold boot bit management
80 * @dev: corresponding STM32 remote processor device
81 * @hold: hold boot value
82 * @return 0 if all went ok, else corresponding -ve error
83 */
84static int stm32_copro_set_hold_boot(struct udevice *dev, bool hold)
85{
86 struct stm32_copro_privdata *priv;
87 uint val;
88 int ret;
89
90 priv = dev_get_priv(dev);
91
92 val = hold ? RCC_GCR_HOLD_BOOT : RCC_GCR_RELEASE_BOOT;
93
94 /*
95 * Note: shall run an SMC call (STM32_SMC_RCC) if platform is secured.
96 * To be updated when the code for this SMC service is available which
97 * is not the case for the time being.
98 */
99 ret = regmap_update_bits(priv->hold_boot_regmap, priv->hold_boot_offset,
100 priv->hold_boot_mask, val);
101 if (ret)
102 dev_err(dev, "failed to set hold boot\n");
103
104 return ret;
105}
106
107/**
108 * stm32_copro_device_to_virt() - Convert device address to virtual address
109 * @dev: corresponding STM32 remote processor device
110 * @da: device address
Lokesh Vutlac08eb932019-09-04 16:01:27 +0530111 * @size: Size of the memory region @da is pointing to
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200112 * @return converted virtual address
113 */
Lokesh Vutlac08eb932019-09-04 16:01:27 +0530114static void *stm32_copro_device_to_virt(struct udevice *dev, ulong da,
115 ulong size)
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200116{
Lokesh Vutlac08eb932019-09-04 16:01:27 +0530117 fdt32_t in_addr = cpu_to_be32(da), end_addr;
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200118 u64 paddr;
119
120 paddr = dev_translate_dma_address(dev, &in_addr);
121 if (paddr == OF_BAD_ADDR) {
122 dev_err(dev, "Unable to convert address %ld\n", da);
123 return NULL;
124 }
125
Lokesh Vutlac08eb932019-09-04 16:01:27 +0530126 end_addr = cpu_to_be32(da + size - 1);
127 if (dev_translate_dma_address(dev, &end_addr) == OF_BAD_ADDR) {
128 dev_err(dev, "Unable to convert address %ld\n", da + size - 1);
129 return NULL;
130 }
131
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200132 return phys_to_virt(paddr);
133}
134
135/**
136 * stm32_copro_load() - Loadup the STM32 remote processor
137 * @dev: corresponding STM32 remote processor device
138 * @addr: Address in memory where image is stored
139 * @size: Size in bytes of the image
140 * @return 0 if all went ok, else corresponding -ve error
141 */
142static int stm32_copro_load(struct udevice *dev, ulong addr, ulong size)
143{
144 struct stm32_copro_privdata *priv;
Fabien Dessenne33fd4192019-10-30 14:38:33 +0100145 ulong rsc_table_size;
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200146 int ret;
147
148 priv = dev_get_priv(dev);
149
150 ret = stm32_copro_set_hold_boot(dev, true);
151 if (ret)
152 return ret;
153
154 ret = reset_assert(&priv->reset_ctl);
155 if (ret) {
156 dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
157 return ret;
158 }
159
Fabien Dessenne33fd4192019-10-30 14:38:33 +0100160 if (rproc_elf32_load_rsc_table(dev, addr, size, &priv->rsc_table_addr,
161 &rsc_table_size)) {
162 priv->rsc_table_addr = 0;
163 dev_warn(dev, "No valid resource table for this firmware\n");
164 }
165
Lokesh Vutla14d963d2019-09-04 16:01:28 +0530166 return rproc_elf32_load_image(dev, addr, size);
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200167}
168
169/**
170 * stm32_copro_start() - Start the STM32 remote processor
171 * @dev: corresponding STM32 remote processor device
172 * @return 0 if all went ok, else corresponding -ve error
173 */
174static int stm32_copro_start(struct udevice *dev)
175{
Fabien Dessenne33fd4192019-10-30 14:38:33 +0100176 struct stm32_copro_privdata *priv;
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200177 int ret;
178
Fabien Dessenne33fd4192019-10-30 14:38:33 +0100179 priv = dev_get_priv(dev);
180
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200181 /* move hold boot from true to false start the copro */
182 ret = stm32_copro_set_hold_boot(dev, false);
183 if (ret)
184 return ret;
185
186 /*
187 * Once copro running, reset hold boot flag to avoid copro
188 * rebooting autonomously
189 */
190 ret = stm32_copro_set_hold_boot(dev, true);
Fabien Dessenne4a4deb82019-10-30 14:38:31 +0100191 writel(ret ? TAMP_COPRO_STATE_OFF : TAMP_COPRO_STATE_CRUN,
192 TAMP_COPRO_STATE);
Fabien Dessenne33fd4192019-10-30 14:38:33 +0100193 if (!ret)
194 /* Store rsc_address in bkp register */
195 writel(priv->rsc_table_addr, TAMP_COPRO_RSC_TBL_ADDRESS);
196
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200197 return ret;
198}
199
200/**
201 * stm32_copro_reset() - Reset the STM32 remote processor
202 * @dev: corresponding STM32 remote processor device
203 * @return 0 if all went ok, else corresponding -ve error
204 */
205static int stm32_copro_reset(struct udevice *dev)
206{
207 struct stm32_copro_privdata *priv;
208 int ret;
209
210 priv = dev_get_priv(dev);
211
212 ret = stm32_copro_set_hold_boot(dev, true);
213 if (ret)
214 return ret;
215
216 ret = reset_assert(&priv->reset_ctl);
217 if (ret) {
218 dev_err(dev, "Unable to assert reset line (ret=%d)\n", ret);
219 return ret;
220 }
221
Fabien Dessenne4a4deb82019-10-30 14:38:31 +0100222 writel(TAMP_COPRO_STATE_OFF, TAMP_COPRO_STATE);
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200223
224 return 0;
225}
226
227/**
228 * stm32_copro_stop() - Stop the STM32 remote processor
229 * @dev: corresponding STM32 remote processor device
230 * @return 0 if all went ok, else corresponding -ve error
231 */
232static int stm32_copro_stop(struct udevice *dev)
233{
234 return stm32_copro_reset(dev);
235}
236
237/**
238 * stm32_copro_is_running() - Is the STM32 remote processor running
239 * @dev: corresponding STM32 remote processor device
Fabien Dessenne4a4deb82019-10-30 14:38:31 +0100240 * @return 0 if the remote processor is running, 1 otherwise
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200241 */
242static int stm32_copro_is_running(struct udevice *dev)
243{
Fabien Dessenne4a4deb82019-10-30 14:38:31 +0100244 return (readl(TAMP_COPRO_STATE) == TAMP_COPRO_STATE_OFF);
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200245}
246
247static const struct dm_rproc_ops stm32_copro_ops = {
248 .load = stm32_copro_load,
249 .start = stm32_copro_start,
250 .stop = stm32_copro_stop,
251 .reset = stm32_copro_reset,
252 .is_running = stm32_copro_is_running,
253 .device_to_virt = stm32_copro_device_to_virt,
254};
255
256static const struct udevice_id stm32_copro_ids[] = {
Patrick Delaunay5d2901a2019-08-02 15:07:18 +0200257 {.compatible = "st,stm32mp1-m4"},
Fabien Dessenne6bed04f2019-05-31 15:11:34 +0200258 {}
259};
260
261U_BOOT_DRIVER(stm32_copro) = {
262 .name = "stm32_m4_proc",
263 .of_match = stm32_copro_ids,
264 .id = UCLASS_REMOTEPROC,
265 .ops = &stm32_copro_ops,
266 .probe = stm32_copro_probe,
267 .priv_auto_alloc_size = sizeof(struct stm32_copro_privdata),
268};