1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/bus.h> 32 #include <sys/malloc.h> 33 34 #include <dev/extres/clk/clk.h> 35 36 #include <arm/ti/clk/ti_clk_clkctrl.h> 37 38 #include "clkdev_if.h" 39 40 #if 0 41 #define DPRINTF(dev, msg...) device_printf(dev, msg) 42 #else 43 #define DPRINTF(dev, msg...) 44 #endif 45 46 /* 47 * clknode for clkctrl, implements gate and mux (for gpioc) 48 */ 49 50 #define GPIO_X_GDBCLK_MASK 0x00040000 51 #define IDLEST_MASK 0x00030000 52 #define MODULEMODE_MASK 0x00000003 53 54 #define GPIOX_GDBCLK_ENABLE 0x00040000 55 #define GPIOX_GDBCLK_DISABLE 0x00000000 56 #define IDLEST_FUNC 0x00000000 57 #define IDLEST_TRANS 0x00010000 58 #define IDLEST_IDLE 0x00020000 59 #define IDLEST_DISABLE 0x00030000 60 61 #define MODULEMODE_DISABLE 0x0 62 #define MODULEMODE_ENABLE 0x2 63 64 struct ti_clkctrl_clknode_sc { 65 device_t dev; 66 bool gdbclk; 67 /* omap4-cm range.host + ti,clkctrl reg[0] */ 68 uint32_t register_offset; 69 }; 70 71 #define WRITE4(_clk, off, val) \ 72 CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) 73 #define READ4(_clk, off, val) \ 74 CLKDEV_READ_4(clknode_get_device(_clk), off, val) 75 #define DEVICE_LOCK(_clk) \ 76 CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) 77 #define DEVICE_UNLOCK(_clk) \ 78 CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) 79 80 static int 81 ti_clkctrl_init(struct clknode *clk, device_t dev) 82 { 83 struct ti_clkctrl_clknode_sc *sc; 84 85 sc = clknode_get_softc(clk); 86 sc->dev = dev; 87 88 clknode_init_parent_idx(clk, 0); 89 return (0); 90 } 91 92 static int 93 ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable) 94 { 95 struct ti_clkctrl_clknode_sc *sc; 96 uint32_t val, gpio_x_gdbclk; 97 uint32_t timeout = 100; 98 99 sc = clknode_get_softc(clk); 100 101 READ4(clk, sc->register_offset, &val); 102 DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n", 103 val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK, 104 GPIO_X_GDBCLK_MASK | MODULEMODE_MASK); 105 106 if (enable) { 107 val = val & MODULEMODE_MASK; 108 val |= GPIOX_GDBCLK_ENABLE; 109 } else { 110 val = val & MODULEMODE_MASK; 111 val |= GPIOX_GDBCLK_DISABLE; 112 } 113 114 DPRINTF(sc->dev, "val %x\n", val); 115 WRITE4(clk, sc->register_offset, val); 116 117 /* Wait */ 118 while (timeout) { 119 READ4(clk, sc->register_offset, &val); 120 gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK; 121 if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE)) 122 break; 123 else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE)) 124 break; 125 DELAY(10); 126 timeout--; 127 } 128 if (timeout == 0) { 129 device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n"); 130 return (1); 131 } 132 133 return (0); 134 } 135 136 static int 137 ti_clkctrl_set_gate(struct clknode *clk, bool enable) 138 { 139 struct ti_clkctrl_clknode_sc *sc; 140 uint32_t val, idlest, module; 141 uint32_t timeout=100; 142 int err; 143 144 sc = clknode_get_softc(clk); 145 146 if (sc->gdbclk) { 147 err = ti_clkctrl_set_gdbclk_gate(clk, enable); 148 return (err); 149 } 150 151 READ4(clk, sc->register_offset, &val); 152 153 if (enable) 154 WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE); 155 else 156 WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE); 157 158 while (timeout) { 159 READ4(clk, sc->register_offset, &val); 160 idlest = val & IDLEST_MASK; 161 module = val & MODULEMODE_MASK; 162 if (enable && 163 (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) && 164 module == MODULEMODE_ENABLE) 165 break; 166 else if (!enable && 167 idlest == IDLEST_DISABLE && 168 module == MODULEMODE_DISABLE) 169 break; 170 DELAY(10); 171 timeout--; 172 } 173 174 if (timeout == 0) { 175 device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n"); 176 return (1); 177 } 178 179 return (0); 180 } 181 182 static clknode_method_t ti_clkctrl_clknode_methods[] = { 183 /* Device interface */ 184 CLKNODEMETHOD(clknode_init, ti_clkctrl_init), 185 CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate), 186 CLKNODEMETHOD_END 187 }; 188 189 DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class, 190 ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc), 191 clknode_class); 192 193 int 194 ti_clknode_clkctrl_register(struct clkdom *clkdom, 195 struct ti_clk_clkctrl_def *clkdef) 196 { 197 struct clknode *clk; 198 struct ti_clkctrl_clknode_sc *sc; 199 200 clk = clknode_create(clkdom, &ti_clkctrl_clknode_class, 201 &clkdef->clkdef); 202 203 if (clk == NULL) { 204 return (1); 205 } 206 207 sc = clknode_get_softc(clk); 208 sc->register_offset = clkdef->register_offset; 209 sc->gdbclk = clkdef->gdbclk; 210 211 if (clknode_register(clkdom, clk) == NULL) { 212 return (2); 213 } 214 return (0); 215 } 216