1/*-
2 * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/param.h>
28#include <sys/bus.h>
29#include <sys/kernel.h>
30#include <sys/lock.h>
31#include <sys/malloc.h>
32#include <sys/module.h>
33#include <sys/mutex.h>
34#include <sys/rman.h>
35#include <sys/systm.h>
36
37#include <machine/bus.h>
38
39#include <dev/clk/clk.h>
40#include <dev/hwreset/hwreset.h>
41#include <dev/ofw/ofw_bus.h>
42#include <dev/ofw/ofw_bus_subr.h>
43
44#include <arm/nvidia/tegra_pmc.h>
45
46#define	PMC_CNTRL			0x000
47#define	 PMC_CNTRL_CPUPWRGOOD_SEL_MASK		(0x3 << 20)
48#define	 PMC_CNTRL_CPUPWRGOOD_SEL_SHIFT		20
49#define	 PMC_CNTRL_CPUPWRGOOD_EN		(1 << 19)
50#define	 PMC_CNTRL_FUSE_OVERRIDE		(1 << 18)
51#define	 PMC_CNTRL_INTR_POLARITY		(1 << 17)
52#define	 PMC_CNTRL_CPU_PWRREQ_OE		(1 << 16)
53#define	 PMC_CNTRL_CPU_PWRREQ_POLARITY		(1 << 15)
54#define	 PMC_CNTRL_SIDE_EFFECT_LP0		(1 << 14)
55#define	 PMC_CNTRL_AOINIT			(1 << 13)
56#define	 PMC_CNTRL_PWRGATE_DIS			(1 << 12)
57#define	 PMC_CNTRL_SYSCLK_OE			(1 << 11)
58#define	 PMC_CNTRL_SYSCLK_POLARITY		(1 << 10)
59#define	 PMC_CNTRL_PWRREQ_OE			(1 <<  9)
60#define	 PMC_CNTRL_PWRREQ_POLARITY		(1 <<  8)
61#define	 PMC_CNTRL_BLINK_EN			(1 <<  7)
62#define	 PMC_CNTRL_GLITCHDET_DIS		(1 <<  6)
63#define	 PMC_CNTRL_LATCHWAKE_EN			(1 <<  5)
64#define	 PMC_CNTRL_MAIN_RST			(1 <<  4)
65#define	 PMC_CNTRL_KBC_RST			(1 <<  3)
66#define	 PMC_CNTRL_RTC_RST			(1 <<  2)
67#define	 PMC_CNTRL_RTC_CLK_DIS			(1 <<  1)
68#define	 PMC_CNTRL_KBC_CLK_DIS			(1 <<  0)
69
70#define	PMC_DPD_SAMPLE			0x020
71
72#define	PMC_CLAMP_STATUS		0x02C
73#define	  PMC_CLAMP_STATUS_PARTID(x)		(1 << ((x) & 0x1F))
74
75#define	PMC_PWRGATE_TOGGLE		0x030
76#define	 PMC_PWRGATE_TOGGLE_START		(1 << 8)
77#define	 PMC_PWRGATE_TOGGLE_PARTID(x)		(((x) & 0x1F) << 0)
78
79#define	PMC_REMOVE_CLAMPING_CMD		0x034
80#define	  PMC_REMOVE_CLAMPING_CMD_PARTID(x)	(1 << ((x) & 0x1F))
81
82#define	PMC_PWRGATE_STATUS		0x038
83#define	PMC_PWRGATE_STATUS_PARTID(x)		(1 << ((x) & 0x1F))
84
85#define	PMC_SCRATCH0			0x050
86#define	 PMC_SCRATCH0_MODE_RECOVERY		(1 << 31)
87#define	 PMC_SCRATCH0_MODE_BOOTLOADER		(1 << 30)
88#define	 PMC_SCRATCH0_MODE_RCM			(1 << 1)
89#define	 PMC_SCRATCH0_MODE_MASK			(PMC_SCRATCH0_MODE_RECOVERY | \
90						PMC_SCRATCH0_MODE_BOOTLOADER | \
91						PMC_SCRATCH0_MODE_RCM)
92
93#define	PMC_CPUPWRGOOD_TIMER		0x0c8
94#define	PMC_CPUPWROFF_TIMER		0x0cc
95
96#define	PMC_SCRATCH41			0x140
97
98#define	PMC_SENSOR_CTRL			0x1b0
99#define	PMC_SENSOR_CTRL_BLOCK_SCRATCH_WRITE	(1 << 2)
100#define	PMC_SENSOR_CTRL_ENABLE_RST		(1 << 1)
101#define	PMC_SENSOR_CTRL_ENABLE_PG		(1 << 0)
102
103#define	PMC_IO_DPD_REQ			0x1b8
104#define	 PMC_IO_DPD_REQ_CODE_IDLE		(0 << 30)
105#define	 PMC_IO_DPD_REQ_CODE_OFF		(1 << 30)
106#define	 PMC_IO_DPD_REQ_CODE_ON			(2 << 30)
107#define	 PMC_IO_DPD_REQ_CODE_MASK		(3 << 30)
108
109#define	PMC_IO_DPD_STATUS		0x1bc
110#define	 PMC_IO_DPD_STATUS_HDMI			(1 << 28)
111#define	PMC_IO_DPD2_REQ			0x1c0
112#define	PMC_IO_DPD2_STATUS		0x1c4
113#define	 PMC_IO_DPD2_STATUS_HV			(1 << 6)
114#define	PMC_SEL_DPD_TIM			0x1c8
115
116#define	PMC_SCRATCH54			0x258
117#define	PMC_SCRATCH54_DATA_SHIFT		8
118#define	PMC_SCRATCH54_ADDR_SHIFT		0
119
120#define	PMC_SCRATCH55			0x25c
121#define	PMC_SCRATCH55_RST_ENABLE		(1 << 31)
122#define	PMC_SCRATCH55_CNTRL_TYPE		(1 << 30)
123#define	PMC_SCRATCH55_CNTRL_ID_SHIFT		27
124#define	PMC_SCRATCH55_CNTRL_ID_MASK		0x07
125#define	PMC_SCRATCH55_PINMUX_SHIFT		24
126#define	PMC_SCRATCH55_PINMUX_MASK		0x07
127#define	PMC_SCRATCH55_CHECKSUM_SHIFT		16
128#define	PMC_SCRATCH55_CHECKSUM_MASK		0xFF
129#define	PMC_SCRATCH55_16BITOP			(1 << 15)
130#define	PMC_SCRATCH55_I2CSLV1_SHIFT		0
131#define	PMC_SCRATCH55_I2CSLV1_MASK		0x7F
132
133#define	PMC_GPU_RG_CNTRL		0x2d4
134
135#define	WR4(_sc, _r, _v)	bus_write_4((_sc)->mem_res, (_r), (_v))
136#define	RD4(_sc, _r)		bus_read_4((_sc)->mem_res, (_r))
137
138#define	PMC_LOCK(_sc)		mtx_lock(&(_sc)->mtx)
139#define	PMC_UNLOCK(_sc)		mtx_unlock(&(_sc)->mtx)
140#define	PMC_LOCK_INIT(_sc)	mtx_init(&(_sc)->mtx, 			\
141	    device_get_nameunit(_sc->dev), "tegra124_pmc", MTX_DEF)
142#define	PMC_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->mtx);
143#define	PMC_ASSERT_LOCKED(_sc)	mtx_assert(&(_sc)->mtx, MA_OWNED);
144#define	PMC_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->mtx, MA_NOTOWNED);
145
146struct tegra124_pmc_softc {
147	device_t		dev;
148	struct resource		*mem_res;
149	clk_t			clk;
150	struct mtx		mtx;
151
152	uint32_t		rate;
153	enum tegra_suspend_mode suspend_mode;
154	uint32_t		cpu_good_time;
155	uint32_t		cpu_off_time;
156	uint32_t		core_osc_time;
157	uint32_t		core_pmu_time;
158	uint32_t		core_off_time;
159	int			corereq_high;
160	int			sysclkreq_high;
161	int			combined_req;
162	int			cpu_pwr_good_en;
163	uint32_t		lp0_vec_phys;
164	uint32_t		lp0_vec_size;
165};
166
167static struct ofw_compat_data compat_data[] = {
168	{"nvidia,tegra124-pmc",		1},
169	{NULL,				0},
170};
171
172static struct tegra124_pmc_softc *pmc_sc;
173
174static inline struct tegra124_pmc_softc *
175tegra124_pmc_get_sc(void)
176{
177	if (pmc_sc == NULL)
178		panic("To early call to Tegra PMC driver.\n");
179	return (pmc_sc);
180}
181
182static int
183tegra124_pmc_set_powergate(struct tegra124_pmc_softc *sc,
184    enum tegra_powergate_id id, int ena)
185{
186	uint32_t reg;
187	int i;
188
189	PMC_LOCK(sc);
190
191	reg = RD4(sc, PMC_PWRGATE_STATUS) & PMC_PWRGATE_STATUS_PARTID(id);
192	if (((reg != 0) && ena) || ((reg == 0) && !ena)) {
193		PMC_UNLOCK(sc);
194		return (0);
195	}
196
197	for (i = 100; i > 0; i--) {
198		reg = RD4(sc, PMC_PWRGATE_TOGGLE);
199		if ((reg & PMC_PWRGATE_TOGGLE_START) == 0)
200			break;
201		DELAY(1);
202	}
203	if (i <= 0)
204		device_printf(sc->dev,
205		    "Timeout when waiting for TOGGLE_START\n");
206
207	WR4(sc, PMC_PWRGATE_TOGGLE,
208	    PMC_PWRGATE_TOGGLE_START | PMC_PWRGATE_TOGGLE_PARTID(id));
209
210	for (i = 100; i > 0; i--) {
211		reg = RD4(sc, PMC_PWRGATE_TOGGLE);
212		if ((reg & PMC_PWRGATE_TOGGLE_START) == 0)
213			break;
214		DELAY(1);
215	}
216	if (i <= 0)
217		device_printf(sc->dev,
218		    "Timeout when waiting for TOGGLE_START\n");
219		PMC_UNLOCK(sc);
220	return (0);
221}
222
223int
224tegra_powergate_remove_clamping(enum tegra_powergate_id  id)
225{
226	struct tegra124_pmc_softc *sc;
227	uint32_t reg;
228	enum tegra_powergate_id swid;
229	int i;
230
231	sc = tegra124_pmc_get_sc();
232
233	if (id == TEGRA_POWERGATE_3D) {
234		WR4(sc, PMC_GPU_RG_CNTRL, 0);
235		return (0);
236	}
237
238	reg = RD4(sc, PMC_PWRGATE_STATUS);
239	if ((reg & PMC_PWRGATE_STATUS_PARTID(id)) == 0)
240		panic("Attempt to remove clamping for unpowered partition.\n");
241
242	if (id == TEGRA_POWERGATE_PCX)
243		swid = TEGRA_POWERGATE_VDE;
244	else if (id == TEGRA_POWERGATE_VDE)
245		swid = TEGRA_POWERGATE_PCX;
246	else
247		swid = id;
248	WR4(sc, PMC_REMOVE_CLAMPING_CMD, PMC_REMOVE_CLAMPING_CMD_PARTID(swid));
249
250	for (i = 100; i > 0; i--) {
251		reg = RD4(sc, PMC_REMOVE_CLAMPING_CMD);
252		if ((reg & PMC_REMOVE_CLAMPING_CMD_PARTID(swid)) == 0)
253			break;
254		DELAY(1);
255	}
256	if (i <= 0)
257		device_printf(sc->dev, "Timeout when remove clamping\n");
258
259	reg = RD4(sc, PMC_CLAMP_STATUS);
260	if ((reg & PMC_CLAMP_STATUS_PARTID(id)) != 0)
261		panic("Cannot remove clamping\n");
262
263	return (0);
264}
265
266int
267tegra_powergate_is_powered(enum tegra_powergate_id id)
268{
269	struct tegra124_pmc_softc *sc;
270	uint32_t reg;
271
272	sc = tegra124_pmc_get_sc();
273
274	reg = RD4(sc, PMC_PWRGATE_STATUS);
275	return ((reg & PMC_PWRGATE_STATUS_PARTID(id)) ? 1 : 0);
276}
277
278int
279tegra_powergate_power_on(enum tegra_powergate_id id)
280{
281	struct tegra124_pmc_softc *sc;
282	int rv, i;
283
284	sc = tegra124_pmc_get_sc();
285
286	rv = tegra124_pmc_set_powergate(sc, id, 1);
287	if (rv != 0) {
288		device_printf(sc->dev, "Cannot set powergate: %d\n", id);
289		return (rv);
290	}
291
292	for (i = 100; i > 0; i--) {
293		if (tegra_powergate_is_powered(id))
294			break;
295		DELAY(1);
296	}
297	if (i <= 0)
298		device_printf(sc->dev, "Timeout when waiting on power up\n");
299
300	return (rv);
301}
302
303int
304tegra_powergate_power_off(enum tegra_powergate_id id)
305{
306	struct tegra124_pmc_softc *sc;
307	int rv, i;
308
309	sc = tegra124_pmc_get_sc();
310
311	rv = tegra124_pmc_set_powergate(sc, id, 0);
312	if (rv != 0) {
313		device_printf(sc->dev, "Cannot set powergate: %d\n", id);
314		return (rv);
315	}
316	for (i = 100; i > 0; i--) {
317		if (!tegra_powergate_is_powered(id))
318			break;
319		DELAY(1);
320	}
321	if (i <= 0)
322		device_printf(sc->dev, "Timeout when waiting on power off\n");
323
324	return (rv);
325}
326
327int
328tegra_powergate_sequence_power_up(enum tegra_powergate_id id, clk_t clk,
329    hwreset_t rst)
330{
331	struct tegra124_pmc_softc *sc;
332	int rv;
333
334	sc = tegra124_pmc_get_sc();
335
336	rv = hwreset_assert(rst);
337	if (rv != 0) {
338		device_printf(sc->dev, "Cannot assert reset\n");
339		return (rv);
340	}
341
342	rv = clk_stop(clk);
343	if (rv != 0) {
344		device_printf(sc->dev, "Cannot stop clock\n");
345		goto clk_fail;
346	}
347
348	rv = tegra_powergate_power_on(id);
349	if (rv != 0) {
350		device_printf(sc->dev, "Cannot power on powergate\n");
351		goto clk_fail;
352	}
353
354	rv = clk_enable(clk);
355	if (rv != 0) {
356		device_printf(sc->dev, "Cannot enable clock\n");
357		goto clk_fail;
358	}
359	DELAY(20);
360
361	rv = tegra_powergate_remove_clamping(id);
362	if (rv != 0) {
363		device_printf(sc->dev, "Cannot remove clamping\n");
364		goto fail;
365	}
366	rv = hwreset_deassert(rst);
367	if (rv != 0) {
368		device_printf(sc->dev, "Cannot unreset reset\n");
369		goto fail;
370	}
371	return 0;
372
373fail:
374	clk_disable(clk);
375clk_fail:
376	hwreset_assert(rst);
377	tegra_powergate_power_off(id);
378	return (rv);
379}
380
381static int
382tegra124_pmc_parse_fdt(struct tegra124_pmc_softc *sc, phandle_t node)
383{
384	int rv;
385	uint32_t tmp;
386	uint32_t tmparr[2];
387
388	rv = OF_getencprop(node, "nvidia,suspend-mode", &tmp, sizeof(tmp));
389	if (rv > 0) {
390		switch (tmp) {
391		case 0:
392			sc->suspend_mode = TEGRA_SUSPEND_LP0;
393			break;
394
395		case 1:
396			sc->suspend_mode = TEGRA_SUSPEND_LP1;
397			break;
398
399		case 2:
400			sc->suspend_mode = TEGRA_SUSPEND_LP2;
401			break;
402
403		default:
404			sc->suspend_mode = TEGRA_SUSPEND_NONE;
405			break;
406		}
407	}
408
409	rv = OF_getencprop(node, "nvidia,cpu-pwr-good-time", &tmp, sizeof(tmp));
410	if (rv > 0) {
411		sc->cpu_good_time = tmp;
412		sc->suspend_mode = TEGRA_SUSPEND_NONE;
413	}
414
415	rv = OF_getencprop(node, "nvidia,cpu-pwr-off-time", &tmp, sizeof(tmp));
416	if (rv > 0) {
417		sc->cpu_off_time = tmp;
418		sc->suspend_mode = TEGRA_SUSPEND_NONE;
419	}
420
421	rv = OF_getencprop(node, "nvidia,core-pwr-good-time", tmparr,
422	    sizeof(tmparr));
423	if (rv == sizeof(tmparr)) {
424		sc->core_osc_time = tmparr[0];
425		sc->core_pmu_time = tmparr[1];
426		sc->suspend_mode = TEGRA_SUSPEND_NONE;
427	}
428
429	rv = OF_getencprop(node, "nvidia,core-pwr-off-time", &tmp, sizeof(tmp));
430	if (rv > 0) {
431		sc->core_off_time = tmp;
432		sc->suspend_mode = TEGRA_SUSPEND_NONE;
433	}
434
435	sc->corereq_high =
436	    OF_hasprop(node, "nvidia,core-power-req-active-high");
437	sc->sysclkreq_high =
438	    OF_hasprop(node, "nvidia,sys-clock-req-active-high");
439	sc->combined_req =
440	    OF_hasprop(node, "nvidia,combined-power-req");
441	sc->cpu_pwr_good_en =
442	    OF_hasprop(node, "nvidia,cpu-pwr-good-en");
443
444	rv = OF_getencprop(node, "nvidia,lp0-vec", tmparr, sizeof(tmparr));
445	if (rv == sizeof(tmparr)) {
446		sc->lp0_vec_phys = tmparr[0];
447		sc->core_pmu_time = tmparr[1];
448		sc->lp0_vec_size = TEGRA_SUSPEND_NONE;
449		if (sc->suspend_mode == TEGRA_SUSPEND_LP0)
450			sc->suspend_mode = TEGRA_SUSPEND_LP1;
451	}
452	return 0;
453}
454
455static int
456tegra124_pmc_probe(device_t dev)
457{
458
459	if (!ofw_bus_status_okay(dev))
460		return (ENXIO);
461
462	if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
463		return (ENXIO);
464
465	device_set_desc(dev, "Tegra PMC");
466	return (BUS_PROBE_DEFAULT);
467}
468
469static int
470tegra124_pmc_detach(device_t dev)
471{
472
473	/* This device is always present. */
474	return (EBUSY);
475}
476
477static int
478tegra124_pmc_attach(device_t dev)
479{
480	struct tegra124_pmc_softc *sc;
481	int rid, rv;
482	uint32_t reg;
483	phandle_t node;
484
485	sc = device_get_softc(dev);
486	sc->dev = dev;
487	node = ofw_bus_get_node(dev);
488
489	rv = tegra124_pmc_parse_fdt(sc, node);
490	if (rv != 0) {
491		device_printf(sc->dev, "Cannot parse FDT data\n");
492		return (rv);
493	}
494
495	rv = clk_get_by_ofw_name(sc->dev, 0, "pclk", &sc->clk);
496	if (rv != 0) {
497		device_printf(sc->dev, "Cannot get \"pclk\" clock\n");
498		return (ENXIO);
499	}
500
501	rid = 0;
502	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
503	    RF_ACTIVE);
504	if (sc->mem_res == NULL) {
505		device_printf(dev, "Cannot allocate memory resources\n");
506		return (ENXIO);
507	}
508
509	PMC_LOCK_INIT(sc);
510
511	/* Enable CPU power request. */
512	reg = RD4(sc, PMC_CNTRL);
513	reg |= PMC_CNTRL_CPU_PWRREQ_OE;
514	WR4(sc, PMC_CNTRL, reg);
515
516	/* Set sysclk output polarity */
517	reg = RD4(sc, PMC_CNTRL);
518	if (sc->sysclkreq_high)
519		reg &= ~PMC_CNTRL_SYSCLK_POLARITY;
520	else
521		reg |= PMC_CNTRL_SYSCLK_POLARITY;
522	WR4(sc, PMC_CNTRL, reg);
523
524	/* Enable sysclk request. */
525	reg = RD4(sc, PMC_CNTRL);
526	reg |= PMC_CNTRL_SYSCLK_OE;
527	WR4(sc, PMC_CNTRL, reg);
528
529	/*
530	 * Remove HDMI from deep power down mode.
531	 * XXX mote this to HDMI driver
532	 */
533	reg = RD4(sc, PMC_IO_DPD_STATUS);
534	reg &= ~ PMC_IO_DPD_STATUS_HDMI;
535	WR4(sc, PMC_IO_DPD_STATUS, reg);
536
537	reg = RD4(sc, PMC_IO_DPD2_STATUS);
538	reg &= ~ PMC_IO_DPD2_STATUS_HV;
539	WR4(sc, PMC_IO_DPD2_STATUS, reg);
540
541	if (pmc_sc != NULL)
542		panic("tegra124_pmc: double driver attach");
543	pmc_sc = sc;
544	return (0);
545}
546
547static device_method_t tegra124_pmc_methods[] = {
548	/* Device interface */
549	DEVMETHOD(device_probe,		tegra124_pmc_probe),
550	DEVMETHOD(device_attach,	tegra124_pmc_attach),
551	DEVMETHOD(device_detach,	tegra124_pmc_detach),
552
553	DEVMETHOD_END
554};
555
556static DEFINE_CLASS_0(pmc, tegra124_pmc_driver, tegra124_pmc_methods,
557    sizeof(struct tegra124_pmc_softc));
558EARLY_DRIVER_MODULE(tegra124_pmc, simplebus, tegra124_pmc_driver, NULL, NULL,
559    70);
560