1296936Smmel/*- 2296936Smmel * Copyright (c) 2016 Michal Meloun <mmel@FreeBSD.org> 3296936Smmel * All rights reserved. 4296936Smmel * 5296936Smmel * Redistribution and use in source and binary forms, with or without 6296936Smmel * modification, are permitted provided that the following conditions 7296936Smmel * are met: 8296936Smmel * 1. Redistributions of source code must retain the above copyright 9296936Smmel * notice, this list of conditions and the following disclaimer. 10296936Smmel * 2. Redistributions in binary form must reproduce the above copyright 11296936Smmel * notice, this list of conditions and the following disclaimer in the 12296936Smmel * documentation and/or other materials provided with the distribution. 13296936Smmel * 14296936Smmel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15296936Smmel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16296936Smmel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17296936Smmel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18296936Smmel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19296936Smmel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20296936Smmel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21296936Smmel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22296936Smmel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23296936Smmel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24296936Smmel * SUCH DAMAGE. 25296936Smmel */ 26296936Smmel 27296936Smmel#include <sys/cdefs.h> 28296936Smmel__FBSDID("$FreeBSD: stable/11/sys/arm/nvidia/tegra124/tegra124_car.c 317013 2017-04-16 08:21:14Z mmel $"); 29296936Smmel 30296936Smmel#include <sys/param.h> 31296936Smmel#include <sys/systm.h> 32296936Smmel#include <sys/bus.h> 33296936Smmel#include <sys/kernel.h> 34296936Smmel#include <sys/kobj.h> 35296936Smmel#include <sys/module.h> 36296936Smmel#include <sys/malloc.h> 37296936Smmel#include <sys/rman.h> 38296936Smmel#include <sys/lock.h> 39296936Smmel#include <sys/mutex.h> 40296936Smmel 41296936Smmel#include <machine/bus.h> 42296936Smmel#include <machine/cpu.h> 43296936Smmel 44296936Smmel#include <dev/extres/clk/clk_div.h> 45296936Smmel#include <dev/extres/clk/clk_fixed.h> 46296936Smmel#include <dev/extres/clk/clk_gate.h> 47296936Smmel#include <dev/extres/clk/clk_mux.h> 48296936Smmel#include <dev/extres/hwreset/hwreset.h> 49296936Smmel#include <dev/ofw/openfirm.h> 50296936Smmel#include <dev/ofw/ofw_bus.h> 51296936Smmel#include <dev/ofw/ofw_bus_subr.h> 52296936Smmel 53296936Smmel#include <gnu/dts/include/dt-bindings/clock/tegra124-car.h> 54296936Smmel 55296936Smmel#include "clkdev_if.h" 56296936Smmel#include "hwreset_if.h" 57296936Smmel#include "tegra124_car.h" 58296936Smmel 59296936Smmelstatic struct ofw_compat_data compat_data[] = { 60296936Smmel {"nvidia,tegra124-car", 1}, 61296936Smmel {NULL, 0}, 62296936Smmel}; 63296936Smmel 64296936Smmel#define PLIST(x) static const char *x[] 65296936Smmel 66296936Smmel/* Pure multiplexer. */ 67296936Smmel#define MUX(_id, cname, plists, o, s, w) \ 68296936Smmel{ \ 69296936Smmel .clkdef.id = _id, \ 70296936Smmel .clkdef.name = cname, \ 71296936Smmel .clkdef.parent_names = plists, \ 72296936Smmel .clkdef.parent_cnt = nitems(plists), \ 73296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 74296936Smmel .offset = o, \ 75296936Smmel .shift = s, \ 76296936Smmel .width = w, \ 77296936Smmel} 78296936Smmel 79296936Smmel/* Fractional divider (7.1). */ 80296936Smmel#define DIV7_1(_id, cname, plist, o, s) \ 81296936Smmel{ \ 82296936Smmel .clkdef.id = _id, \ 83296936Smmel .clkdef.name = cname, \ 84296936Smmel .clkdef.parent_names = (const char *[]){plist}, \ 85296936Smmel .clkdef.parent_cnt = 1, \ 86296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 87296936Smmel .offset = o, \ 88296936Smmel .i_shift = (s) + 1, \ 89296936Smmel .i_width = 7, \ 90296936Smmel .f_shift = s, \ 91296936Smmel .f_width = 1, \ 92296936Smmel} 93296936Smmel 94296936Smmel/* Integer divider. */ 95296936Smmel#define DIV(_id, cname, plist, o, s, w, f) \ 96296936Smmel{ \ 97296936Smmel .clkdef.id = _id, \ 98296936Smmel .clkdef.name = cname, \ 99296936Smmel .clkdef.parent_names = (const char *[]){plist}, \ 100296936Smmel .clkdef.parent_cnt = 1, \ 101296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 102296936Smmel .offset = o, \ 103296936Smmel .i_shift = s, \ 104296936Smmel .i_width = w, \ 105296936Smmel .div_flags = f, \ 106296936Smmel} 107296936Smmel 108296936Smmel/* Gate in PLL block. */ 109296936Smmel#define GATE_PLL(_id, cname, plist, o, s) \ 110296936Smmel{ \ 111296936Smmel .clkdef.id = _id, \ 112296936Smmel .clkdef.name = cname, \ 113296936Smmel .clkdef.parent_names = (const char *[]){plist}, \ 114296936Smmel .clkdef.parent_cnt = 1, \ 115296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 116296936Smmel .offset = o, \ 117296936Smmel .shift = s, \ 118296936Smmel .mask = 3, \ 119296936Smmel .on_value = 3, \ 120296936Smmel .off_value = 0, \ 121296936Smmel} 122296936Smmel 123296936Smmel/* Standard gate. */ 124296936Smmel#define GATE(_id, cname, plist, o, s) \ 125296936Smmel{ \ 126296936Smmel .clkdef.id = _id, \ 127296936Smmel .clkdef.name = cname, \ 128296936Smmel .clkdef.parent_names = (const char *[]){plist}, \ 129296936Smmel .clkdef.parent_cnt = 1, \ 130296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 131296936Smmel .offset = o, \ 132296936Smmel .shift = s, \ 133296936Smmel .mask = 1, \ 134296936Smmel .on_value = 1, \ 135296936Smmel .off_value = 0, \ 136296936Smmel} 137296936Smmel 138296936Smmel/* Inverted gate. */ 139296936Smmel#define GATE_INV(_id, cname, plist, o, s) \ 140296936Smmel{ \ 141296936Smmel .clkdef.id = _id, \ 142296936Smmel .clkdef.name = cname, \ 143296936Smmel .clkdef.parent_names = (const char *[]){plist}, \ 144296936Smmel .clkdef.parent_cnt = 1, \ 145296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 146296936Smmel .offset = o, \ 147296936Smmel .shift = s, \ 148296936Smmel .mask = 1, \ 149296936Smmel .on_value = 0, \ 150296936Smmel .off_value = 1, \ 151296936Smmel} 152296936Smmel 153296936Smmel/* Fixed rate clock. */ 154296936Smmel#define FRATE(_id, cname, _freq) \ 155296936Smmel{ \ 156296936Smmel .clkdef.id = _id, \ 157296936Smmel .clkdef.name = cname, \ 158296936Smmel .clkdef.parent_names = NULL, \ 159296936Smmel .clkdef.parent_cnt = 0, \ 160296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 161296936Smmel .freq = _freq, \ 162296936Smmel} 163296936Smmel 164296936Smmel/* Fixed rate multipier/divider. */ 165296936Smmel#define FACT(_id, cname, pname, _mult, _div) \ 166296936Smmel{ \ 167296936Smmel .clkdef.id = _id, \ 168296936Smmel .clkdef.name = cname, \ 169296936Smmel .clkdef.parent_names = (const char *[]){pname}, \ 170296936Smmel .clkdef.parent_cnt = 1, \ 171296936Smmel .clkdef.flags = CLK_NODE_STATIC_STRINGS, \ 172296936Smmel .mult = _mult, \ 173296936Smmel .div = _div, \ 174296936Smmel} 175296936Smmel 176296936Smmelstatic uint32_t osc_freqs[16] = { 177296936Smmel [0] = 13000000, 178296936Smmel [1] = 16800000, 179296936Smmel [4] = 19200000, 180296936Smmel [5] = 38400000, 181296936Smmel [8] = 12000000, 182296936Smmel [9] = 48000000, 183296936Smmel [12] = 260000000, 184296936Smmel}; 185296936Smmel 186296936Smmel 187296936Smmel/* Parent lists. */ 188296936SmmelPLIST(mux_pll_srcs) = {"osc_div_clk", NULL, "pllP_out0", NULL}; /* FIXME */ 189296936SmmelPLIST(mux_plle_src1) = {"osc_div_clk", "pllP_out0"}; 190296936SmmelPLIST(mux_plle_src) = {"pllE_src1", "pllREFE_out"}; 191296936SmmelPLIST(mux_plld_out0_plld2_out0) = {"pllD_out0", "pllD2_out0"}; 192317012SmmelPLIST(mux_xusb_hs) = {"xusb_ss_div2", "pllU_60"}; 193296936SmmelPLIST(mux_xusb_ss) = {"pc_xusb_ss", "osc_div_clk"}; 194296936Smmel 195296936Smmel 196296936Smmel/* Clocks ajusted online. */ 197296936Smmelstatic struct clk_fixed_def fixed_clk_m = 198317012Smmel FRATE(TEGRA124_CLK_CLK_M, "clk_m", 12000000); 199296936Smmelstatic struct clk_fixed_def fixed_osc_div_clk = 200296936Smmel FACT(0, "osc_div_clk", "clk_m", 1, 1); 201296936Smmel 202296936Smmelstatic struct clk_fixed_def tegra124_fixed_clks[] = { 203296936Smmel /* Core clocks. */ 204296936Smmel FRATE(0, "clk_s", 32768), 205296936Smmel FACT(0, "clk_m_div2", "clk_m", 1, 2), 206296936Smmel FACT(0, "clk_m_div4", "clk_m", 1, 3), 207296936Smmel FACT(0, "pllU_60", "pllU_out", 1, 8), 208296936Smmel FACT(0, "pllU_48", "pllU_out", 1, 10), 209296936Smmel FACT(0, "pllU_12", "pllU_out", 1, 40), 210296936Smmel FACT(TEGRA124_CLK_PLL_D_OUT0, "pllD_out0", "pllD_out", 1, 2), 211296936Smmel FACT(TEGRA124_CLK_PLL_D2_OUT0, "pllD2_out0", "pllD2_out", 1, 1), 212296936Smmel FACT(0, "pllX_out0", "pllX_out", 1, 2), 213296936Smmel FACT(0, "pllC_UD", "pllC_out0", 1, 1), 214296936Smmel FACT(0, "pllM_UD", "pllM_out0", 1, 1), 215296936Smmel 216296936Smmel /* Audio clocks. */ 217296936Smmel FRATE(0, "audio0", 10000000), 218296936Smmel FRATE(0, "audio1", 10000000), 219296936Smmel FRATE(0, "audio2", 10000000), 220296936Smmel FRATE(0, "audio3", 10000000), 221296936Smmel FRATE(0, "audio4", 10000000), 222296936Smmel FRATE(0, "ext_vimclk", 10000000), 223317012Smmel 224317012Smmel /* XUSB */ 225317012Smmel FACT(TEGRA124_CLK_XUSB_SS_DIV2, "xusb_ss_div2", "xusb_ss", 1, 2), 226317012Smmel 227296936Smmel}; 228296936Smmel 229296936Smmel 230296936Smmelstatic struct clk_mux_def tegra124_mux_clks[] = { 231296936Smmel /* Core clocks. */ 232296936Smmel MUX(0, "pllD2_src", mux_pll_srcs, PLLD2_BASE, 25, 2), 233296936Smmel MUX(0, "pllDP_src", mux_pll_srcs, PLLDP_BASE, 25, 2), 234296936Smmel MUX(0, "pllC4_src", mux_pll_srcs, PLLC4_BASE, 25, 2), 235296936Smmel MUX(0, "pllE_src1", mux_plle_src1, PLLE_AUX, 2, 1), 236296936Smmel MUX(0, "pllE_src", mux_plle_src, PLLE_AUX, 28, 1), 237296936Smmel 238296936Smmel /* Base peripheral clocks. */ 239296936Smmel MUX(0, "dsia_mux", mux_plld_out0_plld2_out0, PLLD_BASE, 25, 1), 240296936Smmel MUX(0, "dsib_mux", mux_plld_out0_plld2_out0, PLLD2_BASE, 25, 1), 241296936Smmel 242296936Smmel /* USB. */ 243317012Smmel MUX(TEGRA124_CLK_XUSB_HS_SRC, "xusb_hs", mux_xusb_hs, CLK_SOURCE_XUSB_SS, 25, 1), 244296936Smmel MUX(0, "xusb_ss_mux", mux_xusb_ss, CLK_SOURCE_XUSB_SS, 24, 1), 245296936Smmel 246296936Smmel}; 247296936Smmel 248296936Smmel 249296936Smmelstatic struct clk_gate_def tegra124_gate_clks[] = { 250296936Smmel /* Core clocks. */ 251296936Smmel GATE_PLL(0, "pllC_out1", "pllC_out1_div", PLLC_OUT, 0), 252296936Smmel GATE_PLL(0, "pllM_out1", "pllM_out1_div", PLLM_OUT, 0), 253317012Smmel GATE_PLL(TEGRA124_CLK_PLL_U_480M, "pllU_480", "pllU_out", PLLU_BASE, 22), 254296936Smmel GATE_PLL(0, "pllP_outX0", "pllP_outX0_div", PLLP_RESHIFT, 0), 255296936Smmel GATE_PLL(0, "pllP_out1", "pllP_out1_div", PLLP_OUTA, 0), 256296936Smmel GATE_PLL(0, "pllP_out2", "pllP_out2_div", PLLP_OUTA, 16), 257296936Smmel GATE_PLL(0, "pllP_out3", "pllP_out3_div", PLLP_OUTB, 0), 258296936Smmel GATE_PLL(0, "pllP_out4", "pllP_out4_div", PLLP_OUTB, 16), 259296936Smmel GATE_PLL(0, "pllP_out5", "pllP_out5_div", PLLP_OUTC, 16), 260296936Smmel GATE_PLL(0, "pllA_out0", "pllA_out1_div", PLLA_OUT, 0), 261296936Smmel 262296936Smmel /* Base peripheral clocks. */ 263296936Smmel GATE(TEGRA124_CLK_CML0, "cml0", "pllE_out0", PLLE_AUX, 0), 264296936Smmel GATE(TEGRA124_CLK_CML1, "cml1", "pllE_out0", PLLE_AUX, 1), 265296936Smmel GATE_INV(TEGRA124_CLK_HCLK, "hclk", "hclk_div", CLK_SYSTEM_RATE, 7), 266296936Smmel GATE_INV(TEGRA124_CLK_PCLK, "pclk", "pclk_div", CLK_SYSTEM_RATE, 3), 267296936Smmel}; 268296936Smmel 269296936Smmelstatic struct clk_div_def tegra124_div_clks[] = { 270296936Smmel /* Core clocks. */ 271296936Smmel DIV7_1(0, "pllC_out1_div", "pllC_out0", PLLC_OUT, 2), 272296936Smmel DIV7_1(0, "pllM_out1_div", "pllM_out0", PLLM_OUT, 8), 273296936Smmel DIV7_1(0, "pllP_outX0_div", "pllP_out0", PLLP_RESHIFT, 2), 274296936Smmel DIV7_1(0, "pllP_out1_div", "pllP_out0", PLLP_OUTA, 8), 275296936Smmel DIV7_1(0, "pllP_out2_div", "pllP_out0", PLLP_OUTA, 24), 276296936Smmel DIV7_1(0, "pllP_out3_div", "pllP_out0", PLLP_OUTB, 8), 277296936Smmel DIV7_1(0, "pllP_out4_div", "pllP_out0", PLLP_OUTB, 24), 278296936Smmel DIV7_1(0, "pllP_out5_div", "pllP_out0", PLLP_OUTC, 24), 279296936Smmel DIV7_1(0, "pllA_out1_div", "pllA_out", PLLA_OUT, 8), 280296936Smmel 281296936Smmel /* Base peripheral clocks. */ 282296936Smmel DIV(0, "hclk_div", "sclk", CLK_SYSTEM_RATE, 4, 2, 0), 283296936Smmel DIV(0, "pclk_div", "hclk", CLK_SYSTEM_RATE, 0, 2, 0), 284296936Smmel}; 285296936Smmel 286296936Smmel/* Initial setup table. */ 287296936Smmelstatic struct tegra124_init_item clk_init_table[] = { 288296936Smmel /* clock, partent, frequency, enable */ 289296936Smmel {"uarta", "pllP_out0", 408000000, 0}, 290296936Smmel {"uartb", "pllP_out0", 408000000, 0}, 291296936Smmel {"uartc", "pllP_out0", 408000000, 0}, 292296936Smmel {"uartd", "pllP_out0", 408000000, 0}, 293296936Smmel {"pllA_out", NULL, 282240000, 1}, 294296936Smmel {"pllA_out0", NULL, 11289600, 1}, 295296936Smmel {"extperiph1", "pllA_out0", 0, 1}, 296296936Smmel {"i2s0", "pllA_out0", 11289600, 0}, 297296936Smmel {"i2s1", "pllA_out0", 11289600, 0}, 298296936Smmel {"i2s2", "pllA_out0", 11289600, 0}, 299296936Smmel {"i2s3", "pllA_out0", 11289600, 0}, 300296936Smmel {"i2s4", "pllA_out0", 11289600, 0}, 301296936Smmel {"vde", "pllP_out0", 0, 0}, 302296936Smmel {"host1x", "pllP_out0", 136000000, 1}, 303296936Smmel {"sclk", "pllP_out2", 102000000, 1}, 304296936Smmel {"dvfs_soc", "pllP_out0", 51000000, 1}, 305296936Smmel {"dvfs_ref", "pllP_out0", 51000000, 1}, 306296936Smmel {"pllC_out0", NULL, 600000000, 0}, 307296936Smmel {"pllC_out1", NULL, 100000000, 0}, 308296936Smmel {"spi4", "pllP_out0", 12000000, 1}, 309296936Smmel {"tsec", "pllC3_out0", 0, 0}, 310296936Smmel {"msenc", "pllC3_out0", 0, 0}, 311296936Smmel {"pllREFE_out", NULL, 672000000, 0}, 312296936Smmel {"pc_xusb_ss", "pllU_480", 120000000, 0}, 313296936Smmel {"xusb_ss", "pc_xusb_ss", 120000000, 0}, 314296936Smmel {"pc_xusb_fs", "pllU_48", 48000000, 0}, 315296936Smmel {"xusb_hs", "pllU_60", 60000000, 0}, 316296936Smmel {"pc_xusb_falcon", "pllREFE_out", 224000000, 0}, 317296936Smmel {"xusb_core_host", "pllREFE_out", 112000000, 0}, 318296936Smmel {"sata", "pllP_out0", 102000000, 0}, 319296936Smmel {"sata_oob", "pllP_out0", 204000000, 0}, 320296936Smmel {"sata_cold", NULL, 0, 1}, 321296936Smmel {"emc", NULL, 0, 1}, 322296936Smmel {"mselect", NULL, 0, 1}, 323296936Smmel {"csite", NULL, 0, 1}, 324296936Smmel {"tsensor", "clk_m", 400000, 0}, 325296936Smmel 326296936Smmel /* tegra124 only*/ 327296936Smmel {"soc_therm", "pllP_out0", 51000000, 0}, 328296936Smmel {"cclk_g", NULL, 0, 1}, 329296936Smmel {"hda", "pllP_out0", 102000000, 0}, 330296936Smmel {"hda2codec_2x", "pllP_out0", 48000000, 0}, 331296936Smmel}; 332296936Smmel 333296936Smmelstatic void 334296936Smmelinit_divs(struct tegra124_car_softc *sc, struct clk_div_def *clks, int nclks) 335296936Smmel{ 336296936Smmel int i, rv; 337296936Smmel 338296936Smmel for (i = 0; i < nclks; i++) { 339296936Smmel rv = clknode_div_register(sc->clkdom, clks + i); 340296936Smmel if (rv != 0) 341296936Smmel panic("clk_div_register failed"); 342296936Smmel } 343296936Smmel} 344296936Smmel 345296936Smmelstatic void 346296936Smmelinit_gates(struct tegra124_car_softc *sc, struct clk_gate_def *clks, int nclks) 347296936Smmel{ 348296936Smmel int i, rv; 349296936Smmel 350296936Smmel 351296936Smmel for (i = 0; i < nclks; i++) { 352296936Smmel rv = clknode_gate_register(sc->clkdom, clks + i); 353296936Smmel if (rv != 0) 354296936Smmel panic("clk_gate_register failed"); 355296936Smmel } 356296936Smmel} 357296936Smmel 358296936Smmelstatic void 359296936Smmelinit_muxes(struct tegra124_car_softc *sc, struct clk_mux_def *clks, int nclks) 360296936Smmel{ 361296936Smmel int i, rv; 362296936Smmel 363296936Smmel 364296936Smmel for (i = 0; i < nclks; i++) { 365296936Smmel rv = clknode_mux_register(sc->clkdom, clks + i); 366296936Smmel if (rv != 0) 367296936Smmel panic("clk_mux_register failed"); 368296936Smmel } 369296936Smmel} 370296936Smmel 371296936Smmelstatic void 372296936Smmelinit_fixeds(struct tegra124_car_softc *sc, struct clk_fixed_def *clks, 373296936Smmel int nclks) 374296936Smmel{ 375296936Smmel int i, rv; 376296936Smmel uint32_t val; 377296936Smmel int osc_idx; 378296936Smmel 379296936Smmel CLKDEV_READ_4(sc->dev, OSC_CTRL, &val); 380296936Smmel osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT; 381296936Smmel fixed_clk_m.freq = osc_freqs[osc_idx]; 382296936Smmel if (fixed_clk_m.freq == 0) 383296936Smmel panic("Undefined input frequency"); 384296936Smmel rv = clknode_fixed_register(sc->clkdom, &fixed_clk_m); 385296936Smmel if (rv != 0) panic("clk_fixed_register failed"); 386296936Smmel 387296936Smmel val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; 388296936Smmel fixed_osc_div_clk.div = 1 << val; 389296936Smmel rv = clknode_fixed_register(sc->clkdom, &fixed_osc_div_clk); 390296936Smmel if (rv != 0) panic("clk_fixed_register failed"); 391296936Smmel 392296936Smmel for (i = 0; i < nclks; i++) { 393296936Smmel rv = clknode_fixed_register(sc->clkdom, clks + i); 394296936Smmel if (rv != 0) 395296936Smmel panic("clk_fixed_register failed"); 396296936Smmel } 397296936Smmel} 398296936Smmel 399296936Smmelstatic void 400296936Smmelpostinit_clock(struct tegra124_car_softc *sc) 401296936Smmel{ 402296936Smmel int i; 403296936Smmel struct tegra124_init_item *tbl; 404296936Smmel struct clknode *clknode; 405296936Smmel int rv; 406296936Smmel 407296936Smmel for (i = 0; i < nitems(clk_init_table); i++) { 408296936Smmel tbl = &clk_init_table[i]; 409296936Smmel 410296936Smmel clknode = clknode_find_by_name(tbl->name); 411296936Smmel if (clknode == NULL) { 412296936Smmel device_printf(sc->dev, "Cannot find clock %s\n", 413296936Smmel tbl->name); 414296936Smmel continue; 415296936Smmel } 416296936Smmel if (tbl->parent != NULL) { 417296936Smmel rv = clknode_set_parent_by_name(clknode, tbl->parent); 418296936Smmel if (rv != 0) { 419296936Smmel device_printf(sc->dev, 420296936Smmel "Cannot set parent for %s (to %s): %d\n", 421296936Smmel tbl->name, tbl->parent, rv); 422296936Smmel continue; 423296936Smmel } 424296936Smmel } 425296936Smmel if (tbl->frequency != 0) { 426296936Smmel rv = clknode_set_freq(clknode, tbl->frequency, 0 , 9999); 427296936Smmel if (rv != 0) { 428296936Smmel device_printf(sc->dev, 429296936Smmel "Cannot set frequency for %s: %d\n", 430296936Smmel tbl->name, rv); 431296936Smmel continue; 432296936Smmel } 433296936Smmel } 434296936Smmel if (tbl->enable!= 0) { 435296936Smmel rv = clknode_enable(clknode); 436296936Smmel if (rv != 0) { 437296936Smmel device_printf(sc->dev, 438296936Smmel "Cannot enable %s: %d\n", tbl->name, rv); 439296936Smmel continue; 440296936Smmel } 441296936Smmel } 442296936Smmel } 443296936Smmel} 444296936Smmel 445296936Smmelstatic void 446296936Smmelregister_clocks(device_t dev) 447296936Smmel{ 448296936Smmel struct tegra124_car_softc *sc; 449296936Smmel 450296936Smmel sc = device_get_softc(dev); 451296936Smmel sc->clkdom = clkdom_create(dev); 452296936Smmel if (sc->clkdom == NULL) 453296936Smmel panic("clkdom == NULL"); 454296936Smmel 455296936Smmel tegra124_init_plls(sc); 456296936Smmel init_fixeds(sc, tegra124_fixed_clks, nitems(tegra124_fixed_clks)); 457296936Smmel init_muxes(sc, tegra124_mux_clks, nitems(tegra124_mux_clks)); 458296936Smmel init_divs(sc, tegra124_div_clks, nitems(tegra124_div_clks)); 459296936Smmel init_gates(sc, tegra124_gate_clks, nitems(tegra124_gate_clks)); 460296936Smmel tegra124_periph_clock(sc); 461296936Smmel tegra124_super_mux_clock(sc); 462296936Smmel clkdom_finit(sc->clkdom); 463296936Smmel clkdom_xlock(sc->clkdom); 464296936Smmel postinit_clock(sc); 465296936Smmel clkdom_unlock(sc->clkdom); 466296936Smmel if (bootverbose) 467296936Smmel clkdom_dump(sc->clkdom); 468296936Smmel} 469296936Smmel 470296936Smmelstatic int 471296936Smmeltegra124_car_clkdev_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 472296936Smmel{ 473296936Smmel struct tegra124_car_softc *sc; 474296936Smmel 475296936Smmel sc = device_get_softc(dev); 476296936Smmel *val = bus_read_4(sc->mem_res, addr); 477296936Smmel return (0); 478296936Smmel} 479296936Smmel 480296936Smmelstatic int 481296936Smmeltegra124_car_clkdev_write_4(device_t dev, bus_addr_t addr, uint32_t val) 482296936Smmel{ 483296936Smmel struct tegra124_car_softc *sc; 484296936Smmel 485296936Smmel sc = device_get_softc(dev); 486296936Smmel bus_write_4(sc->mem_res, addr, val); 487296936Smmel return (0); 488296936Smmel} 489296936Smmel 490296936Smmelstatic int 491296936Smmeltegra124_car_clkdev_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask, 492296936Smmel uint32_t set_mask) 493296936Smmel{ 494296936Smmel struct tegra124_car_softc *sc; 495296936Smmel uint32_t reg; 496296936Smmel 497296936Smmel sc = device_get_softc(dev); 498296936Smmel reg = bus_read_4(sc->mem_res, addr); 499296936Smmel reg &= ~clear_mask; 500296936Smmel reg |= set_mask; 501296936Smmel bus_write_4(sc->mem_res, addr, reg); 502296936Smmel return (0); 503296936Smmel} 504296936Smmel 505296936Smmelstatic void 506296936Smmeltegra124_car_clkdev_device_lock(device_t dev) 507296936Smmel{ 508296936Smmel struct tegra124_car_softc *sc; 509296936Smmel 510296936Smmel sc = device_get_softc(dev); 511296936Smmel mtx_lock(&sc->mtx); 512296936Smmel} 513296936Smmel 514296936Smmelstatic void 515296936Smmeltegra124_car_clkdev_device_unlock(device_t dev) 516296936Smmel{ 517296936Smmel struct tegra124_car_softc *sc; 518296936Smmel 519296936Smmel sc = device_get_softc(dev); 520296936Smmel mtx_unlock(&sc->mtx); 521296936Smmel} 522296936Smmel 523296936Smmelstatic int 524296936Smmeltegra124_car_detach(device_t dev) 525296936Smmel{ 526296936Smmel 527296936Smmel device_printf(dev, "Error: Clock driver cannot be detached\n"); 528296936Smmel return (EBUSY); 529296936Smmel} 530296936Smmel 531296936Smmelstatic int 532296936Smmeltegra124_car_probe(device_t dev) 533296936Smmel{ 534296936Smmel 535296936Smmel if (!ofw_bus_status_okay(dev)) 536296936Smmel return (ENXIO); 537296936Smmel 538296936Smmel if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) { 539296936Smmel device_set_desc(dev, "Tegra Clock Driver"); 540296936Smmel return (BUS_PROBE_DEFAULT); 541296936Smmel } 542296936Smmel 543296936Smmel return (ENXIO); 544296936Smmel} 545296936Smmel 546296936Smmelstatic int 547296936Smmeltegra124_car_attach(device_t dev) 548296936Smmel{ 549296936Smmel struct tegra124_car_softc *sc = device_get_softc(dev); 550296936Smmel int rid, rv; 551296936Smmel 552296936Smmel sc->dev = dev; 553296936Smmel 554296936Smmel mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); 555296936Smmel sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 556296936Smmel 557296936Smmel /* Resource setup. */ 558296936Smmel rid = 0; 559296936Smmel sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 560296936Smmel RF_ACTIVE); 561296936Smmel if (!sc->mem_res) { 562296936Smmel device_printf(dev, "cannot allocate memory resource\n"); 563296936Smmel rv = ENXIO; 564296936Smmel goto fail; 565296936Smmel } 566296936Smmel 567296936Smmel register_clocks(dev); 568296936Smmel hwreset_register_ofw_provider(dev); 569296936Smmel return (0); 570296936Smmel 571296936Smmelfail: 572296936Smmel if (sc->mem_res) 573296936Smmel bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); 574296936Smmel 575296936Smmel return (rv); 576296936Smmel} 577296936Smmel 578296936Smmelstatic int 579296936Smmeltegra124_car_hwreset_assert(device_t dev, intptr_t id, bool value) 580296936Smmel{ 581296936Smmel struct tegra124_car_softc *sc = device_get_softc(dev); 582296936Smmel 583296936Smmel return (tegra124_hwreset_by_idx(sc, id, value)); 584296936Smmel} 585296936Smmel 586296936Smmelstatic device_method_t tegra124_car_methods[] = { 587296936Smmel /* Device interface */ 588296936Smmel DEVMETHOD(device_probe, tegra124_car_probe), 589296936Smmel DEVMETHOD(device_attach, tegra124_car_attach), 590296936Smmel DEVMETHOD(device_detach, tegra124_car_detach), 591296936Smmel 592296936Smmel /* Clkdev interface*/ 593296936Smmel DEVMETHOD(clkdev_read_4, tegra124_car_clkdev_read_4), 594296936Smmel DEVMETHOD(clkdev_write_4, tegra124_car_clkdev_write_4), 595296936Smmel DEVMETHOD(clkdev_modify_4, tegra124_car_clkdev_modify_4), 596296936Smmel DEVMETHOD(clkdev_device_lock, tegra124_car_clkdev_device_lock), 597296936Smmel DEVMETHOD(clkdev_device_unlock, tegra124_car_clkdev_device_unlock), 598296936Smmel 599296936Smmel /* Reset interface */ 600296936Smmel DEVMETHOD(hwreset_assert, tegra124_car_hwreset_assert), 601296936Smmel 602296936Smmel DEVMETHOD_END 603296936Smmel}; 604296936Smmel 605296936Smmelstatic devclass_t tegra124_car_devclass; 606308335Smmelstatic DEFINE_CLASS_0(car, tegra124_car_driver, tegra124_car_methods, 607308335Smmel sizeof(struct tegra124_car_softc)); 608296936SmmelEARLY_DRIVER_MODULE(tegra124_car, simplebus, tegra124_car_driver, 609308335Smmel tegra124_car_devclass, NULL, NULL, BUS_PASS_TIMER); 610