xref: /freebsd/sys/arm/ti/clk/ti_clk_clkctrl.c (revision be82b3a0bf72ed3b5f01ac9fcd8dcd3802e3c742)
10050ea24SMichal Meloun /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
30050ea24SMichal Meloun  *
40050ea24SMichal Meloun  * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
50050ea24SMichal Meloun  *
60050ea24SMichal Meloun  * Redistribution and use in source and binary forms, with or without
70050ea24SMichal Meloun  * modification, are permitted provided that the following conditions
80050ea24SMichal Meloun  * are met:
90050ea24SMichal Meloun  * 1. Redistributions of source code must retain the above copyright
100050ea24SMichal Meloun  *    notice, this list of conditions and the following disclaimer.
110050ea24SMichal Meloun  * 2. Redistributions in binary form must reproduce the above copyright
120050ea24SMichal Meloun  *    notice, this list of conditions and the following disclaimer in the
130050ea24SMichal Meloun  *    documentation and/or other materials provided with the distribution.
140050ea24SMichal Meloun  *
150050ea24SMichal Meloun  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
160050ea24SMichal Meloun  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
170050ea24SMichal Meloun  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
180050ea24SMichal Meloun  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
190050ea24SMichal Meloun  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
200050ea24SMichal Meloun  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
210050ea24SMichal Meloun  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
220050ea24SMichal Meloun  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
230050ea24SMichal Meloun  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
240050ea24SMichal Meloun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
250050ea24SMichal Meloun  * SUCH DAMAGE.
260050ea24SMichal Meloun  */
270050ea24SMichal Meloun 
280050ea24SMichal Meloun #include <sys/param.h>
290050ea24SMichal Meloun #include <sys/systm.h>
300050ea24SMichal Meloun #include <sys/bus.h>
310050ea24SMichal Meloun #include <sys/malloc.h>
320050ea24SMichal Meloun 
33*be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
340050ea24SMichal Meloun 
350050ea24SMichal Meloun #include <arm/ti/clk/ti_clk_clkctrl.h>
360050ea24SMichal Meloun 
370050ea24SMichal Meloun #include "clkdev_if.h"
380050ea24SMichal Meloun 
390050ea24SMichal Meloun #if 0
400050ea24SMichal Meloun #define DPRINTF(dev, msg...) device_printf(dev, msg)
410050ea24SMichal Meloun #else
420050ea24SMichal Meloun #define DPRINTF(dev, msg...)
430050ea24SMichal Meloun #endif
440050ea24SMichal Meloun 
450050ea24SMichal Meloun /*
460050ea24SMichal Meloun  * clknode for clkctrl, implements gate and mux (for gpioc)
470050ea24SMichal Meloun  */
480050ea24SMichal Meloun 
490050ea24SMichal Meloun #define GPIO_X_GDBCLK_MASK	0x00040000
500050ea24SMichal Meloun #define IDLEST_MASK		0x00030000
510050ea24SMichal Meloun #define MODULEMODE_MASK		0x00000003
520050ea24SMichal Meloun 
530050ea24SMichal Meloun #define GPIOX_GDBCLK_ENABLE	0x00040000
540050ea24SMichal Meloun #define GPIOX_GDBCLK_DISABLE	0x00000000
550050ea24SMichal Meloun #define IDLEST_FUNC		0x00000000
560050ea24SMichal Meloun #define IDLEST_TRANS		0x00010000
570050ea24SMichal Meloun #define IDLEST_IDLE		0x00020000
580050ea24SMichal Meloun #define IDLEST_DISABLE		0x00030000
590050ea24SMichal Meloun 
600050ea24SMichal Meloun #define MODULEMODE_DISABLE	0x0
610050ea24SMichal Meloun #define MODULEMODE_ENABLE	0x2
620050ea24SMichal Meloun 
630050ea24SMichal Meloun struct ti_clkctrl_clknode_sc {
640050ea24SMichal Meloun 	device_t	dev;
650050ea24SMichal Meloun 	bool		gdbclk;
660050ea24SMichal Meloun 	/* omap4-cm range.host + ti,clkctrl reg[0] */
670050ea24SMichal Meloun 	uint32_t	register_offset;
680050ea24SMichal Meloun };
690050ea24SMichal Meloun 
700050ea24SMichal Meloun #define	WRITE4(_clk, off, val)						\
710050ea24SMichal Meloun 	CLKDEV_WRITE_4(clknode_get_device(_clk), off, val)
720050ea24SMichal Meloun #define	READ4(_clk, off, val)						\
730050ea24SMichal Meloun 	CLKDEV_READ_4(clknode_get_device(_clk), off, val)
740050ea24SMichal Meloun #define	DEVICE_LOCK(_clk)						\
750050ea24SMichal Meloun 	CLKDEV_DEVICE_LOCK(clknode_get_device(_clk))
760050ea24SMichal Meloun #define	DEVICE_UNLOCK(_clk)						\
770050ea24SMichal Meloun 	CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk))
780050ea24SMichal Meloun 
790050ea24SMichal Meloun static int
ti_clkctrl_init(struct clknode * clk,device_t dev)800050ea24SMichal Meloun ti_clkctrl_init(struct clknode *clk, device_t dev)
810050ea24SMichal Meloun {
820050ea24SMichal Meloun 	struct ti_clkctrl_clknode_sc *sc;
830050ea24SMichal Meloun 
840050ea24SMichal Meloun 	sc = clknode_get_softc(clk);
850050ea24SMichal Meloun 	sc->dev = dev;
860050ea24SMichal Meloun 
870050ea24SMichal Meloun 	clknode_init_parent_idx(clk, 0);
880050ea24SMichal Meloun 	return (0);
890050ea24SMichal Meloun }
900050ea24SMichal Meloun 
910050ea24SMichal Meloun static int
ti_clkctrl_set_gdbclk_gate(struct clknode * clk,bool enable)920050ea24SMichal Meloun ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable)
930050ea24SMichal Meloun {
940050ea24SMichal Meloun 	struct ti_clkctrl_clknode_sc *sc;
950050ea24SMichal Meloun 	uint32_t val, gpio_x_gdbclk;
960050ea24SMichal Meloun 	uint32_t timeout = 100;
970050ea24SMichal Meloun 
980050ea24SMichal Meloun 	sc = clknode_get_softc(clk);
990050ea24SMichal Meloun 
1000050ea24SMichal Meloun 	READ4(clk, sc->register_offset, &val);
1010050ea24SMichal Meloun 	DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n",
1020050ea24SMichal Meloun 	    val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK,
1030050ea24SMichal Meloun 	    GPIO_X_GDBCLK_MASK | MODULEMODE_MASK);
1040050ea24SMichal Meloun 
1050050ea24SMichal Meloun 	if (enable) {
1060050ea24SMichal Meloun 		val = val & MODULEMODE_MASK;
1070050ea24SMichal Meloun 		val |= GPIOX_GDBCLK_ENABLE;
1080050ea24SMichal Meloun 	} else {
1090050ea24SMichal Meloun 		val = val & MODULEMODE_MASK;
1100050ea24SMichal Meloun 		val |= GPIOX_GDBCLK_DISABLE;
1110050ea24SMichal Meloun 	}
1120050ea24SMichal Meloun 
1130050ea24SMichal Meloun 	DPRINTF(sc->dev, "val %x\n", val);
1140050ea24SMichal Meloun 	WRITE4(clk, sc->register_offset, val);
1150050ea24SMichal Meloun 
1160050ea24SMichal Meloun 	/* Wait */
1170050ea24SMichal Meloun 	while (timeout) {
1180050ea24SMichal Meloun 		READ4(clk, sc->register_offset, &val);
1190050ea24SMichal Meloun 		gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK;
1200050ea24SMichal Meloun 		if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE))
1210050ea24SMichal Meloun 			break;
1220050ea24SMichal Meloun 		else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE))
1230050ea24SMichal Meloun 			break;
1240050ea24SMichal Meloun 		DELAY(10);
1250050ea24SMichal Meloun 		timeout--;
1260050ea24SMichal Meloun 	}
1270050ea24SMichal Meloun 	if (timeout == 0) {
1280050ea24SMichal Meloun 		device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n");
1290050ea24SMichal Meloun 		return (1);
1300050ea24SMichal Meloun 	}
1310050ea24SMichal Meloun 
1320050ea24SMichal Meloun 	return (0);
1330050ea24SMichal Meloun }
1340050ea24SMichal Meloun 
1350050ea24SMichal Meloun static int
ti_clkctrl_set_gate(struct clknode * clk,bool enable)1360050ea24SMichal Meloun ti_clkctrl_set_gate(struct clknode *clk, bool enable)
1370050ea24SMichal Meloun {
1380050ea24SMichal Meloun 	struct ti_clkctrl_clknode_sc *sc;
1390050ea24SMichal Meloun 	uint32_t	val, idlest, module;
1400050ea24SMichal Meloun 	uint32_t timeout=100;
1410050ea24SMichal Meloun 	int err;
1420050ea24SMichal Meloun 
1430050ea24SMichal Meloun 	sc = clknode_get_softc(clk);
1440050ea24SMichal Meloun 
1450050ea24SMichal Meloun 	if (sc->gdbclk) {
1460050ea24SMichal Meloun 		err = ti_clkctrl_set_gdbclk_gate(clk, enable);
1470050ea24SMichal Meloun 		return (err);
1480050ea24SMichal Meloun 	}
1490050ea24SMichal Meloun 
1500050ea24SMichal Meloun 	READ4(clk, sc->register_offset, &val);
1510050ea24SMichal Meloun 
1520050ea24SMichal Meloun 	if (enable)
1530050ea24SMichal Meloun 		WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE);
1540050ea24SMichal Meloun 	else
1550050ea24SMichal Meloun 		WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE);
1560050ea24SMichal Meloun 
1570050ea24SMichal Meloun 	while (timeout) {
1580050ea24SMichal Meloun 		READ4(clk, sc->register_offset, &val);
1590050ea24SMichal Meloun 		idlest = val & IDLEST_MASK;
1600050ea24SMichal Meloun 		module = val & MODULEMODE_MASK;
1610050ea24SMichal Meloun 		if (enable &&
1620050ea24SMichal Meloun 		    (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) &&
1630050ea24SMichal Meloun 		    module == MODULEMODE_ENABLE)
1640050ea24SMichal Meloun 			break;
1650050ea24SMichal Meloun 		else if (!enable &&
1660050ea24SMichal Meloun 		    idlest == IDLEST_DISABLE &&
1670050ea24SMichal Meloun 		    module == MODULEMODE_DISABLE)
1680050ea24SMichal Meloun 			break;
1690050ea24SMichal Meloun 		DELAY(10);
1700050ea24SMichal Meloun 		timeout--;
1710050ea24SMichal Meloun 	}
1720050ea24SMichal Meloun 
1730050ea24SMichal Meloun 	if (timeout == 0) {
1740050ea24SMichal Meloun 		device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n");
1750050ea24SMichal Meloun 		return (1);
1760050ea24SMichal Meloun 	}
1770050ea24SMichal Meloun 
1780050ea24SMichal Meloun 	return (0);
1790050ea24SMichal Meloun }
1800050ea24SMichal Meloun 
1810050ea24SMichal Meloun static clknode_method_t ti_clkctrl_clknode_methods[] = {
1820050ea24SMichal Meloun 	/* Device interface */
1830050ea24SMichal Meloun 	CLKNODEMETHOD(clknode_init,	ti_clkctrl_init),
1840050ea24SMichal Meloun 	CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate),
1850050ea24SMichal Meloun 	CLKNODEMETHOD_END
1860050ea24SMichal Meloun };
1870050ea24SMichal Meloun 
1880050ea24SMichal Meloun DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class,
1890050ea24SMichal Meloun     ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc),
1900050ea24SMichal Meloun     clknode_class);
1910050ea24SMichal Meloun 
1920050ea24SMichal Meloun int
ti_clknode_clkctrl_register(struct clkdom * clkdom,struct ti_clk_clkctrl_def * clkdef)1930050ea24SMichal Meloun ti_clknode_clkctrl_register(struct clkdom *clkdom,
1940050ea24SMichal Meloun     struct ti_clk_clkctrl_def *clkdef)
1950050ea24SMichal Meloun {
1960050ea24SMichal Meloun 	struct clknode *clk;
1970050ea24SMichal Meloun 	struct ti_clkctrl_clknode_sc *sc;
1980050ea24SMichal Meloun 
1990050ea24SMichal Meloun 	clk = clknode_create(clkdom, &ti_clkctrl_clknode_class,
2000050ea24SMichal Meloun 	    &clkdef->clkdef);
2010050ea24SMichal Meloun 
2020050ea24SMichal Meloun 	if (clk == NULL) {
2030050ea24SMichal Meloun 		return (1);
2040050ea24SMichal Meloun 	}
2050050ea24SMichal Meloun 
2060050ea24SMichal Meloun 	sc = clknode_get_softc(clk);
2070050ea24SMichal Meloun 	sc->register_offset = clkdef->register_offset;
2080050ea24SMichal Meloun 	sc->gdbclk = clkdef->gdbclk;
2090050ea24SMichal Meloun 
2100050ea24SMichal Meloun 	if (clknode_register(clkdom, clk) == NULL) {
2110050ea24SMichal Meloun 		return (2);
2120050ea24SMichal Meloun 	}
2130050ea24SMichal Meloun 	return (0);
2140050ea24SMichal Meloun }
215