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