1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6 * Tero Kristo <t-kristo@ti.com>
9 #include <linux/kernel.h>
10 #include <linux/device.h>
12 #include <linux/iopoll.h>
14 #include <linux/of_device.h>
15 #include <linux/platform_device.h>
16 #include <linux/reset-controller.h>
17 #include <linux/delay.h>
19 #include <linux/platform_data/ti-prm.h>
26 struct omap_prm_data
{
29 const char *clkdm_name
;
32 const struct omap_rst_map
*rstmap
;
37 const struct omap_prm_data
*data
;
41 struct omap_reset_data
{
42 struct reset_controller_dev rcdev
;
46 struct clockdomain
*clkdm
;
50 #define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev)
52 #define OMAP_MAX_RESETS 8
53 #define OMAP_RESET_MAX_WAIT 10000
55 #define OMAP_PRM_HAS_RSTCTRL BIT(0)
56 #define OMAP_PRM_HAS_RSTST BIT(1)
57 #define OMAP_PRM_HAS_NO_CLKDM BIT(2)
59 #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST)
61 static const struct omap_rst_map rst_map_0
[] = {
62 { .rst
= 0, .st
= 0 },
66 static const struct omap_rst_map rst_map_01
[] = {
67 { .rst
= 0, .st
= 0 },
68 { .rst
= 1, .st
= 1 },
72 static const struct omap_rst_map rst_map_012
[] = {
73 { .rst
= 0, .st
= 0 },
74 { .rst
= 1, .st
= 1 },
75 { .rst
= 2, .st
= 2 },
79 static const struct omap_prm_data omap4_prm_data
[] = {
80 { .name
= "tesla", .base
= 0x4a306400, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
81 { .name
= "core", .base
= 0x4a306700, .rstctrl
= 0x210, .rstst
= 0x214, .clkdm_name
= "ducati", .rstmap
= rst_map_012
},
82 { .name
= "ivahd", .base
= 0x4a306f00, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
},
83 { .name
= "device", .base
= 0x4a307b00, .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= rst_map_01
, .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
},
87 static const struct omap_prm_data omap5_prm_data
[] = {
88 { .name
= "dsp", .base
= 0x4ae06400, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
89 { .name
= "core", .base
= 0x4ae06700, .rstctrl
= 0x210, .rstst
= 0x214, .clkdm_name
= "ipu", .rstmap
= rst_map_012
},
90 { .name
= "iva", .base
= 0x4ae07200, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
},
91 { .name
= "device", .base
= 0x4ae07c00, .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= rst_map_01
, .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
},
95 static const struct omap_prm_data dra7_prm_data
[] = {
96 { .name
= "dsp1", .base
= 0x4ae06400, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
97 { .name
= "ipu", .base
= 0x4ae06500, .rstctrl
= 0x10, .rstst
= 0x14, .clkdm_name
= "ipu1", .rstmap
= rst_map_012
},
98 { .name
= "core", .base
= 0x4ae06700, .rstctrl
= 0x210, .rstst
= 0x214, .clkdm_name
= "ipu2", .rstmap
= rst_map_012
},
99 { .name
= "iva", .base
= 0x4ae06f00, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_012
},
100 { .name
= "dsp2", .base
= 0x4ae07b00, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
101 { .name
= "eve1", .base
= 0x4ae07b40, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
102 { .name
= "eve2", .base
= 0x4ae07b80, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
103 { .name
= "eve3", .base
= 0x4ae07bc0, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
104 { .name
= "eve4", .base
= 0x4ae07c00, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_01
},
108 static const struct omap_rst_map am3_per_rst_map
[] = {
113 static const struct omap_rst_map am3_wkup_rst_map
[] = {
114 { .rst
= 3, .st
= 5 },
118 static const struct omap_prm_data am3_prm_data
[] = {
119 { .name
= "per", .base
= 0x44e00c00, .rstctrl
= 0x0, .rstmap
= am3_per_rst_map
, .flags
= OMAP_PRM_HAS_RSTCTRL
, .clkdm_name
= "pruss_ocp" },
120 { .name
= "wkup", .base
= 0x44e00d00, .rstctrl
= 0x0, .rstst
= 0xc, .rstmap
= am3_wkup_rst_map
, .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
},
121 { .name
= "device", .base
= 0x44e00f00, .rstctrl
= 0x0, .rstst
= 0x8, .rstmap
= rst_map_01
, .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
},
122 { .name
= "gfx", .base
= 0x44e01100, .rstctrl
= 0x4, .rstst
= 0x14, .rstmap
= rst_map_0
, .clkdm_name
= "gfx_l3" },
126 static const struct omap_rst_map am4_per_rst_map
[] = {
127 { .rst
= 1, .st
= 0 },
131 static const struct omap_rst_map am4_device_rst_map
[] = {
132 { .rst
= 0, .st
= 1 },
133 { .rst
= 1, .st
= 0 },
137 static const struct omap_prm_data am4_prm_data
[] = {
138 { .name
= "gfx", .base
= 0x44df0400, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= rst_map_0
, .clkdm_name
= "gfx_l3" },
139 { .name
= "per", .base
= 0x44df0800, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= am4_per_rst_map
, .clkdm_name
= "pruss_ocp" },
140 { .name
= "wkup", .base
= 0x44df2000, .rstctrl
= 0x10, .rstst
= 0x14, .rstmap
= am3_wkup_rst_map
, .flags
= OMAP_PRM_HAS_NO_CLKDM
},
141 { .name
= "device", .base
= 0x44df4000, .rstctrl
= 0x0, .rstst
= 0x4, .rstmap
= am4_device_rst_map
, .flags
= OMAP_PRM_HAS_RSTCTRL
| OMAP_PRM_HAS_NO_CLKDM
},
145 static const struct of_device_id omap_prm_id_table
[] = {
146 { .compatible
= "ti,omap4-prm-inst", .data
= omap4_prm_data
},
147 { .compatible
= "ti,omap5-prm-inst", .data
= omap5_prm_data
},
148 { .compatible
= "ti,dra7-prm-inst", .data
= dra7_prm_data
},
149 { .compatible
= "ti,am3-prm-inst", .data
= am3_prm_data
},
150 { .compatible
= "ti,am4-prm-inst", .data
= am4_prm_data
},
154 static bool _is_valid_reset(struct omap_reset_data
*reset
, unsigned long id
)
156 if (reset
->mask
& BIT(id
))
162 static int omap_reset_get_st_bit(struct omap_reset_data
*reset
,
165 const struct omap_rst_map
*map
= reset
->prm
->data
->rstmap
;
167 while (map
->rst
>= 0) {
177 static int omap_reset_status(struct reset_controller_dev
*rcdev
,
180 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
182 int st_bit
= omap_reset_get_st_bit(reset
, id
);
183 bool has_rstst
= reset
->prm
->data
->rstst
||
184 (reset
->prm
->data
->flags
& OMAP_PRM_HAS_RSTST
);
186 /* Check if we have rstst */
190 /* Check if hw reset line is asserted */
191 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
196 * Check reset status, high value means reset sequence has been
197 * completed successfully so we can return 0 here (reset deasserted)
199 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstst
);
206 static int omap_reset_assert(struct reset_controller_dev
*rcdev
,
209 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
213 /* assert the reset control line */
214 spin_lock_irqsave(&reset
->lock
, flags
);
215 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
217 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
218 spin_unlock_irqrestore(&reset
->lock
, flags
);
223 static int omap_reset_deassert(struct reset_controller_dev
*rcdev
,
226 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
231 struct ti_prm_platform_data
*pdata
= dev_get_platdata(reset
->dev
);
234 has_rstst
= reset
->prm
->data
->rstst
||
235 (reset
->prm
->data
->flags
& OMAP_PRM_HAS_RSTST
);
238 st_bit
= omap_reset_get_st_bit(reset
, id
);
240 /* Clear the reset status by writing 1 to the status bit */
242 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstst
);
246 pdata
->clkdm_deny_idle(reset
->clkdm
);
248 /* de-assert the reset control line */
249 spin_lock_irqsave(&reset
->lock
, flags
);
250 v
= readl_relaxed(reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
252 writel_relaxed(v
, reset
->prm
->base
+ reset
->prm
->data
->rstctrl
);
253 spin_unlock_irqrestore(&reset
->lock
, flags
);
258 /* wait for the status to be set */
259 ret
= readl_relaxed_poll_timeout(reset
->prm
->base
+
260 reset
->prm
->data
->rstst
,
261 v
, v
& BIT(st_bit
), 1,
262 OMAP_RESET_MAX_WAIT
);
264 pr_err("%s: timedout waiting for %s:%lu\n", __func__
,
265 reset
->prm
->data
->name
, id
);
269 pdata
->clkdm_allow_idle(reset
->clkdm
);
274 static const struct reset_control_ops omap_reset_ops
= {
275 .assert = omap_reset_assert
,
276 .deassert
= omap_reset_deassert
,
277 .status
= omap_reset_status
,
280 static int omap_prm_reset_xlate(struct reset_controller_dev
*rcdev
,
281 const struct of_phandle_args
*reset_spec
)
283 struct omap_reset_data
*reset
= to_omap_reset_data(rcdev
);
285 if (!_is_valid_reset(reset
, reset_spec
->args
[0]))
288 return reset_spec
->args
[0];
291 static int omap_prm_reset_init(struct platform_device
*pdev
,
292 struct omap_prm
*prm
)
294 struct omap_reset_data
*reset
;
295 const struct omap_rst_map
*map
;
296 struct ti_prm_platform_data
*pdata
= dev_get_platdata(&pdev
->dev
);
300 * Check if we have controllable resets. If either rstctrl is non-zero
301 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register
304 if (!prm
->data
->rstctrl
&& !(prm
->data
->flags
& OMAP_PRM_HAS_RSTCTRL
))
307 /* Check if we have the pdata callbacks in place */
308 if (!pdata
|| !pdata
->clkdm_lookup
|| !pdata
->clkdm_deny_idle
||
309 !pdata
->clkdm_allow_idle
)
312 map
= prm
->data
->rstmap
;
316 reset
= devm_kzalloc(&pdev
->dev
, sizeof(*reset
), GFP_KERNEL
);
320 reset
->rcdev
.owner
= THIS_MODULE
;
321 reset
->rcdev
.ops
= &omap_reset_ops
;
322 reset
->rcdev
.of_node
= pdev
->dev
.of_node
;
323 reset
->rcdev
.nr_resets
= OMAP_MAX_RESETS
;
324 reset
->rcdev
.of_xlate
= omap_prm_reset_xlate
;
325 reset
->rcdev
.of_reset_n_cells
= 1;
326 reset
->dev
= &pdev
->dev
;
327 spin_lock_init(&reset
->lock
);
331 sprintf(buf
, "%s_clkdm", prm
->data
->clkdm_name
? prm
->data
->clkdm_name
:
334 if (!(prm
->data
->flags
& OMAP_PRM_HAS_NO_CLKDM
)) {
335 reset
->clkdm
= pdata
->clkdm_lookup(buf
);
340 while (map
->rst
>= 0) {
341 reset
->mask
|= BIT(map
->rst
);
345 return devm_reset_controller_register(&pdev
->dev
, &reset
->rcdev
);
348 static int omap_prm_probe(struct platform_device
*pdev
)
350 struct resource
*res
;
351 const struct omap_prm_data
*data
;
352 struct omap_prm
*prm
;
353 const struct of_device_id
*match
;
355 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
359 match
= of_match_device(omap_prm_id_table
, &pdev
->dev
);
363 prm
= devm_kzalloc(&pdev
->dev
, sizeof(*prm
), GFP_KERNEL
);
369 while (data
->base
!= res
->start
) {
377 prm
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
378 if (IS_ERR(prm
->base
))
379 return PTR_ERR(prm
->base
);
381 return omap_prm_reset_init(pdev
, prm
);
384 static struct platform_driver omap_prm_driver
= {
385 .probe
= omap_prm_probe
,
387 .name
= KBUILD_MODNAME
,
388 .of_match_table
= omap_prm_id_table
,
391 builtin_platform_driver(omap_prm_driver
);