1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Semihalf. 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, 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 * $FreeBSD$ 28 * 29 */ 30 31 #ifndef _PERIPH_H_ 32 #define _PERIPH_H_ 33 34 #include <dev/extres/clk/clk.h> 35 #include <dev/extres/clk/clk_mux.h> 36 #include <dev/extres/clk/clk_div.h> 37 #include <dev/extres/clk/clk_gate.h> 38 39 #define TBG_SEL 0x0 40 #define DIV_SEL0 0x4 41 #define DIV_SEL1 0x8 42 #define DIV_SEL2 0xC 43 #define CLK_SEL 0x10 44 #define CLK_DIS 0x14 45 #define DIV_MASK 0x7 46 47 #define MUX_POS 1 48 #define DIV1_POS 2 49 #define DIV2_POS 3 50 #define GATE_POS 4 51 #define FIXED1_POS 5 52 #define FIXED2_POS 6 53 #define CLK_MUX_POS 7 54 55 #define RD4(_clk, offset, val) \ 56 CLKDEV_READ_4(clknode_get_device(_clk), offset, val) 57 58 #define A37x0_INTERNAL_CLK_ID(_base, _pos) \ 59 ((_base * 10) + (_pos)) 60 61 #define CLK_FULL_DD(_name, _id, _gate_shift, _tbg_mux_shift, \ 62 _clk_mux_shift, _div1_reg, _div2_reg, _div1_shift, _div2_shift, \ 63 _tbg_mux_name, _div1_name, _div2_name, _clk_mux_name) \ 64 { \ 65 .type = CLK_FULL_DD, \ 66 .common_def.device_name = _name, \ 67 .common_def.device_id = _id, \ 68 .clk_def.full_dd.tbg_mux.clkdef.name = _tbg_mux_name, \ 69 .clk_def.full_dd.tbg_mux.offset = TBG_SEL, \ 70 .clk_def.full_dd.tbg_mux.shift = _tbg_mux_shift, \ 71 .clk_def.full_dd.tbg_mux.width = 0x2, \ 72 .clk_def.full_dd.tbg_mux.mux_flags = 0x0, \ 73 .clk_def.full_dd.div1.clkdef.name = _div1_name, \ 74 .clk_def.full_dd.div1.offset = _div1_reg, \ 75 .clk_def.full_dd.div1.i_shift = _div1_shift, \ 76 .clk_def.full_dd.div1.i_width = 0x3, \ 77 .clk_def.full_dd.div1.f_shift = 0x0, \ 78 .clk_def.full_dd.div1.f_width = 0x0, \ 79 .clk_def.full_dd.div1.div_flags = 0x0, \ 80 .clk_def.full_dd.div1.div_table = NULL, \ 81 .clk_def.full_dd.div2.clkdef.name = _div2_name, \ 82 .clk_def.full_dd.div2.offset = _div2_reg, \ 83 .clk_def.full_dd.div2.i_shift = _div2_shift, \ 84 .clk_def.full_dd.div2.i_width = 0x3, \ 85 .clk_def.full_dd.div2.f_shift = 0x0, \ 86 .clk_def.full_dd.div2.f_width = 0x0, \ 87 .clk_def.full_dd.div2.div_flags = 0x0, \ 88 .clk_def.full_dd.div2.div_table = NULL, \ 89 .clk_def.full_dd.clk_mux.clkdef.name = _clk_mux_name, \ 90 .clk_def.full_dd.clk_mux.offset = CLK_SEL, \ 91 .clk_def.full_dd.clk_mux.shift = _clk_mux_shift, \ 92 .clk_def.full_dd.clk_mux.width = 0x1, \ 93 .clk_def.full_dd.clk_mux.mux_flags = 0x0, \ 94 .clk_def.full_dd.gate.clkdef.name = _name, \ 95 .clk_def.full_dd.gate.offset = CLK_DIS, \ 96 .clk_def.full_dd.gate.shift = _gate_shift, \ 97 .clk_def.full_dd.gate.on_value = 0, \ 98 .clk_def.full_dd.gate.off_value = 1, \ 99 .clk_def.full_dd.gate.mask = 0x1, \ 100 .clk_def.full_dd.gate.gate_flags = 0x0 \ 101 } 102 103 #define CLK_FULL(_name, _id, _gate_shift, _tbg_mux_shift, \ 104 _clk_mux_shift, _div1_reg, _div1_shift, _div_table, _tbg_mux_name, \ 105 _div1_name, _clk_mux_name) \ 106 { \ 107 .type = CLK_FULL, \ 108 .common_def.device_name = _name, \ 109 .common_def.device_id = _id, \ 110 .clk_def.full_d.tbg_mux.clkdef.name = _tbg_mux_name, \ 111 .clk_def.full_d.tbg_mux.offset = TBG_SEL, \ 112 .clk_def.full_d.tbg_mux.shift = _tbg_mux_shift, \ 113 .clk_def.full_d.tbg_mux.width = 0x2, \ 114 .clk_def.full_d.tbg_mux.mux_flags = 0x0, \ 115 .clk_def.full_d.div.clkdef.name = _div1_name, \ 116 .clk_def.full_d.div.offset = _div1_reg, \ 117 .clk_def.full_d.div.i_shift = _div1_shift, \ 118 .clk_def.full_d.div.i_width = 0x3, \ 119 .clk_def.full_d.div.f_shift = 0x0, \ 120 .clk_def.full_d.div.f_width = 0x0, \ 121 .clk_def.full_d.div.div_flags = 0x0, \ 122 .clk_def.full_d.div.div_table = _div_table, \ 123 .clk_def.full_d.clk_mux.clkdef.name = _clk_mux_name, \ 124 .clk_def.full_d.clk_mux.offset = CLK_SEL, \ 125 .clk_def.full_d.clk_mux.shift = _clk_mux_shift, \ 126 .clk_def.full_d.clk_mux.width = 0x1, \ 127 .clk_def.full_d.clk_mux.mux_flags = 0x0, \ 128 .clk_def.full_d.gate.clkdef.name = _name, \ 129 .clk_def.full_d.gate.offset = CLK_DIS, \ 130 .clk_def.full_d.gate.shift = _gate_shift, \ 131 .clk_def.full_d.gate.on_value = 0, \ 132 .clk_def.full_d.gate.off_value = 1, \ 133 .clk_def.full_d.gate.mask = 0x1, \ 134 .clk_def.full_d.gate.gate_flags = 0x0 \ 135 } 136 137 #define CLK_CPU(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg, \ 138 _div1_shift, _div_table, _tbg_mux_name, _div1_name) \ 139 { \ 140 .type = CLK_CPU, \ 141 .common_def.device_name = _name, \ 142 .common_def.device_id = _id, \ 143 .clk_def.cpu.tbg_mux.clkdef.name = _tbg_mux_name, \ 144 .clk_def.cpu.tbg_mux.offset = TBG_SEL, \ 145 .clk_def.cpu.tbg_mux.shift = _tbg_mux_shift, \ 146 .clk_def.cpu.tbg_mux.width = 0x2, \ 147 .clk_def.cpu.tbg_mux.mux_flags = 0x0, \ 148 .clk_def.cpu.div.clkdef.name = _div1_name, \ 149 .clk_def.cpu.div.offset = _div1_reg, \ 150 .clk_def.cpu.div.i_shift = _div1_shift, \ 151 .clk_def.cpu.div.i_width = 0x3, \ 152 .clk_def.cpu.div.f_shift = 0x0, \ 153 .clk_def.cpu.div.f_width = 0x0, \ 154 .clk_def.cpu.div.div_flags = 0x0, \ 155 .clk_def.cpu.div.div_table = _div_table, \ 156 .clk_def.cpu.clk_mux.clkdef.name = _name, \ 157 .clk_def.cpu.clk_mux.offset = CLK_SEL, \ 158 .clk_def.cpu.clk_mux.shift = _clk_mux_shift, \ 159 .clk_def.cpu.clk_mux.width = 0x1, \ 160 .clk_def.cpu.clk_mux.mux_flags = 0x0, \ 161 } 162 163 #define CLK_GATE(_name, _id, _gate_shift, _pname) \ 164 { \ 165 .type = CLK_GATE, \ 166 .common_def.device_name = _name, \ 167 .common_def.device_id = _id, \ 168 .common_def.pname = _pname, \ 169 .clk_def.gate.gate.clkdef.name = _name, \ 170 .clk_def.gate.gate.clkdef.parent_cnt = 1, \ 171 .clk_def.gate.gate.offset = CLK_DIS, \ 172 .clk_def.gate.gate.shift = _gate_shift, \ 173 .clk_def.gate.gate.on_value = 0, \ 174 .clk_def.gate.gate.off_value = 1, \ 175 .clk_def.gate.gate.mask = 0x1, \ 176 .clk_def.gate.gate.gate_flags = 0x0 \ 177 } 178 179 #define CLK_MDD(_name, _id, _tbg_mux_shift, _clk_mux_shift, _div1_reg, \ 180 _div2_reg, _div1_shift, _div2_shift, _tbg_mux_name, _div1_name, \ 181 _div2_name) \ 182 { \ 183 .type = CLK_MDD, \ 184 .common_def.device_name = _name, \ 185 .common_def.device_id = _id, \ 186 .clk_def.mdd.tbg_mux.clkdef.name = _tbg_mux_name, \ 187 .clk_def.mdd.tbg_mux.offset = TBG_SEL, \ 188 .clk_def.mdd.tbg_mux.shift = _tbg_mux_shift, \ 189 .clk_def.mdd.tbg_mux.width = 0x2, \ 190 .clk_def.mdd.tbg_mux.mux_flags = 0x0, \ 191 .clk_def.mdd.div1.clkdef.name = _div1_name, \ 192 .clk_def.mdd.div1.offset = _div1_reg, \ 193 .clk_def.mdd.div1.i_shift = _div1_shift, \ 194 .clk_def.mdd.div1.i_width = 0x3, \ 195 .clk_def.mdd.div1.f_shift = 0x0, \ 196 .clk_def.mdd.div1.f_width = 0x0, \ 197 .clk_def.mdd.div1.div_flags = 0x0, \ 198 .clk_def.mdd.div1.div_table = NULL, \ 199 .clk_def.mdd.div2.clkdef.name = _div2_name, \ 200 .clk_def.mdd.div2.offset = _div2_reg, \ 201 .clk_def.mdd.div2.i_shift = _div2_shift, \ 202 .clk_def.mdd.div2.i_width = 0x3, \ 203 .clk_def.mdd.div2.f_shift = 0x0, \ 204 .clk_def.mdd.div2.f_width = 0x0, \ 205 .clk_def.mdd.div2.div_flags = 0x0, \ 206 .clk_def.mdd.div2.div_table = NULL, \ 207 .clk_def.mdd.clk_mux.clkdef.name = _name, \ 208 .clk_def.mdd.clk_mux.offset = CLK_SEL, \ 209 .clk_def.mdd.clk_mux.shift = _clk_mux_shift, \ 210 .clk_def.mdd.clk_mux.width = 0x1, \ 211 .clk_def.mdd.clk_mux.mux_flags = 0x0 \ 212 } 213 214 #define CLK_MUX_GATE(_name, _id, _gate_shift, _mux_shift, _pname, \ 215 _mux_name, _fixed_name) \ 216 { \ 217 .type = CLK_MUX_GATE, \ 218 .common_def.device_name = _name, \ 219 .common_def.device_id = _id, \ 220 .common_def.pname = _pname, \ 221 .clk_def.mux_gate.mux.clkdef.name = _mux_name, \ 222 .clk_def.mux_gate.mux.offset = TBG_SEL, \ 223 .clk_def.mux_gate.mux.shift = _mux_shift, \ 224 .clk_def.mux_gate.mux.width = 0x1, \ 225 .clk_def.mux_gate.mux.mux_flags = 0x0, \ 226 .clk_def.mux_gate.gate.clkdef.name = _name, \ 227 .clk_def.mux_gate.gate.offset = CLK_DIS, \ 228 .clk_def.mux_gate.gate.shift = _gate_shift, \ 229 .clk_def.mux_gate.gate.on_value = 0, \ 230 .clk_def.mux_gate.gate.off_value = 1, \ 231 .clk_def.mux_gate.gate.mask = 0x1, \ 232 .clk_def.mux_gate.gate.gate_flags = 0x0, \ 233 .clk_def.mux_gate.fixed.clkdef.name = _fixed_name \ 234 } 235 236 #define CLK_MUX_GATE_FIXED(_name, _id, _gate_shift, _mux_shift, \ 237 _mux_name, _gate_name, _fixed1_name) \ 238 { \ 239 .type = CLK_MUX_GATE_FIXED, \ 240 .common_def.device_name = _name, \ 241 .common_def.device_id = _id, \ 242 .clk_def.mux_gate_fixed.mux.clkdef.name = _mux_name, \ 243 .clk_def.mux_gate_fixed.mux.offset = TBG_SEL, \ 244 .clk_def.mux_gate_fixed.mux.shift = _mux_shift, \ 245 .clk_def.mux_gate_fixed.mux.width = 0x1, \ 246 .clk_def.mux_gate_fixed.mux.mux_flags = 0x0, \ 247 .clk_def.mux_gate_fixed.gate.clkdef.name = _gate_name, \ 248 .clk_def.mux_gate_fixed.gate.offset = CLK_DIS, \ 249 .clk_def.mux_gate_fixed.gate.shift = _gate_shift, \ 250 .clk_def.mux_gate_fixed.gate.on_value = 0, \ 251 .clk_def.mux_gate_fixed.gate.off_value = 1, \ 252 .clk_def.mux_gate_fixed.gate.mask = 0x1, \ 253 .clk_def.mux_gate_fixed.gate.gate_flags = 0x0, \ 254 .clk_def.mux_gate_fixed.fixed1.clkdef.name = _fixed1_name, \ 255 .clk_def.mux_gate_fixed.fixed2.clkdef.name = _name \ 256 } 257 258 #define CLK_FIXED(_name, _id, _gate_shift, _mux_shift, _mux_name, \ 259 _fixed_name) \ 260 { \ 261 .type = CLK_FIXED, \ 262 .common_def.device_name = _name, \ 263 .common_def.device_id = _id, \ 264 .clk_def.fixed.mux.clkdef.name = _mux_name, \ 265 .clk_def.fixed.mux.offset = TBG_SEL, \ 266 .clk_def.fixed.mux.shift = _mux_shift, \ 267 .clk_def.fixed.mux.width = 0x1, \ 268 .clk_def.fixed.mux.mux_flags = 0x0, \ 269 .clk_def.fixed.gate.clkdef.name = _name, \ 270 .clk_def.fixed.gate.offset = CLK_DIS, \ 271 .clk_def.fixed.gate.shift = _gate_shift, \ 272 .clk_def.fixed.gate.on_value = 0, \ 273 .clk_def.fixed.gate.off_value = 1, \ 274 .clk_def.fixed.gate.mask = 0x1, \ 275 .clk_def.fixed.gate.gate_flags = 0x0, \ 276 .clk_def.fixed.fixed.clkdef.name = _fixed_name \ 277 } 278 279 struct a37x0_periph_clk_softc { 280 device_t dev; 281 struct resource *res; 282 struct clkdom *clkdom; 283 struct mtx mtx; 284 struct a37x0_periph_clknode_def *devices; 285 int device_count; 286 }; 287 288 struct a37x0_periph_clk_dd_def { 289 struct clk_mux_def tbg_mux; 290 struct clk_div_def div1; 291 struct clk_div_def div2; 292 struct clk_mux_def clk_mux; 293 struct clk_gate_def gate; 294 }; 295 296 struct a37x0_periph_clk_cpu_def { 297 struct clk_mux_def tbg_mux; 298 struct clk_div_def div; 299 struct clk_mux_def clk_mux; 300 }; 301 302 struct a37x0_periph_clk_d_def { 303 struct clk_mux_def tbg_mux; 304 struct clk_div_def div; 305 struct clk_mux_def clk_mux; 306 struct clk_gate_def gate; 307 }; 308 309 struct a37x0_periph_clk_fixed_def { 310 struct clk_mux_def mux; 311 struct clk_fixed_def fixed; 312 struct clk_gate_def gate; 313 }; 314 315 struct a37x0_periph_clk_gate_def { 316 struct clk_gate_def gate; 317 }; 318 319 struct a37x0_periph_clk_mux_dd_def { 320 struct clk_mux_def tbg_mux; 321 struct clk_div_def div1; 322 struct clk_div_def div2; 323 struct clk_mux_def clk_mux; 324 }; 325 326 struct a37x0_periph_clk_mux_div_def { 327 struct clk_mux_def mux; 328 struct clk_div_def div; 329 }; 330 331 struct a37x0_periph_clk_mux_gate_def { 332 struct clk_mux_def mux; 333 struct clk_fixed_def fixed; 334 struct clk_gate_def gate; 335 }; 336 337 struct a37x0_periph_clk_mux_gate_fixed_def { 338 struct clk_fixed_def fixed1; 339 struct clk_mux_def mux; 340 struct clk_gate_def gate; 341 struct clk_fixed_def fixed2; 342 }; 343 344 enum a37x0_periph_clk_type { 345 /* Double divider clock */ 346 CLK_FULL_DD, 347 /* Single divider clock */ 348 CLK_FULL, 349 /* Gate clock */ 350 CLK_GATE, 351 /* Mux, gate clock */ 352 CLK_MUX_GATE, 353 /* CPU clock */ 354 CLK_CPU, 355 /* Clock with fixed frequency divider */ 356 CLK_FIXED, 357 /* Clock with double divider, without gate */ 358 CLK_MDD, 359 /* Clock with two fixed frequency dividers */ 360 CLK_MUX_GATE_FIXED 361 }; 362 363 struct a37x0_periph_common_defs { 364 char *device_name; 365 int device_id; 366 int tbg_cnt; 367 const char *pname; 368 const char **tbgs; 369 const char *xtal; 370 }; 371 372 union a37x0_periph_clocks_defs { 373 struct a37x0_periph_clk_dd_def full_dd; 374 struct a37x0_periph_clk_d_def full_d; 375 struct a37x0_periph_clk_gate_def gate; 376 struct a37x0_periph_clk_mux_gate_def mux_gate; 377 struct a37x0_periph_clk_cpu_def cpu; 378 struct a37x0_periph_clk_fixed_def fixed; 379 struct a37x0_periph_clk_mux_dd_def mdd; 380 struct a37x0_periph_clk_mux_gate_fixed_def mux_gate_fixed; 381 }; 382 383 struct a37x0_periph_clknode_def { 384 enum a37x0_periph_clk_type type; 385 struct a37x0_periph_common_defs common_def; 386 union a37x0_periph_clocks_defs clk_def; 387 }; 388 389 int a37x0_periph_create_mux(struct clkdom *, 390 struct clk_mux_def *, int); 391 int a37x0_periph_create_div(struct clkdom *, 392 struct clk_div_def *, int); 393 int a37x0_periph_create_gate(struct clkdom *, 394 struct clk_gate_def *, int); 395 void a37x0_periph_set_props(struct clknode_init_def *, const char **, 396 unsigned int); 397 int a37x0_periph_d_register_full_clk_dd(struct clkdom *, 398 struct a37x0_periph_clknode_def *); 399 int a37x0_periph_d_register_full_clk(struct clkdom *, 400 struct a37x0_periph_clknode_def *); 401 int a37x0_periph_d_register_periph_cpu(struct clkdom *, 402 struct a37x0_periph_clknode_def *); 403 int a37x0_periph_fixed_register_fixed(struct clkdom*, 404 struct a37x0_periph_clknode_def *); 405 int a37x0_periph_gate_register_gate(struct clkdom *, 406 struct a37x0_periph_clknode_def *); 407 int a37x0_periph_d_register_mdd(struct clkdom *, 408 struct a37x0_periph_clknode_def *); 409 int a37x0_periph_d_register_mux_div_clk(struct clkdom *, 410 struct a37x0_periph_clknode_def *); 411 int a37x0_periph_register_mux_gate(struct clkdom *, 412 struct a37x0_periph_clknode_def *); 413 int a37x0_periph_register_mux_gate_fixed(struct clkdom *, 414 struct a37x0_periph_clknode_def *); 415 416 int a37x0_periph_clk_read_4(device_t, bus_addr_t, uint32_t *); 417 void a37x0_periph_clk_device_unlock(device_t); 418 void a37x0_periph_clk_device_lock(device_t); 419 int a37x0_periph_clk_attach(device_t); 420 int a37x0_periph_clk_detach(device_t); 421 422 #endif 423