1*54b96380SRuslan Bukin /*- 2*54b96380SRuslan Bukin * SPDX-License-Identifier: BSD-2-Clause 3*54b96380SRuslan Bukin * 4*54b96380SRuslan Bukin * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> 5*54b96380SRuslan Bukin * 6*54b96380SRuslan Bukin * This work was supported by Innovate UK project 105694, "Digital Security 7*54b96380SRuslan Bukin * by Design (DSbD) Technology Platform Prototype". 8*54b96380SRuslan Bukin * 9*54b96380SRuslan Bukin * Redistribution and use in source and binary forms, with or without 10*54b96380SRuslan Bukin * modification, are permitted provided that the following conditions 11*54b96380SRuslan Bukin * are met: 12*54b96380SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 13*54b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer. 14*54b96380SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 15*54b96380SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 16*54b96380SRuslan Bukin * documentation and/or other materials provided with the distribution. 17*54b96380SRuslan Bukin * 18*54b96380SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*54b96380SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*54b96380SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*54b96380SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*54b96380SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*54b96380SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*54b96380SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*54b96380SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*54b96380SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*54b96380SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*54b96380SRuslan Bukin * SUCH DAMAGE. 29*54b96380SRuslan Bukin */ 30*54b96380SRuslan Bukin 31*54b96380SRuslan Bukin #include <sys/cdefs.h> 32*54b96380SRuslan Bukin __FBSDID("$FreeBSD$"); 33*54b96380SRuslan Bukin 34*54b96380SRuslan Bukin #include <sys/param.h> 35*54b96380SRuslan Bukin #include <sys/systm.h> 36*54b96380SRuslan Bukin #include <sys/bus.h> 37*54b96380SRuslan Bukin #include <sys/cpu.h> 38*54b96380SRuslan Bukin #include <sys/kernel.h> 39*54b96380SRuslan Bukin #include <sys/module.h> 40*54b96380SRuslan Bukin 41*54b96380SRuslan Bukin #include <dev/extres/clk/clk.h> 42*54b96380SRuslan Bukin #include <dev/fdt/simplebus.h> 43*54b96380SRuslan Bukin #include <dev/fdt/fdt_common.h> 44*54b96380SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 45*54b96380SRuslan Bukin 46*54b96380SRuslan Bukin #include "scmi.h" 47*54b96380SRuslan Bukin #include "scmi_protocols.h" 48*54b96380SRuslan Bukin #include "scmi_clk.h" 49*54b96380SRuslan Bukin 50*54b96380SRuslan Bukin struct scmi_clk_softc { 51*54b96380SRuslan Bukin device_t dev; 52*54b96380SRuslan Bukin device_t scmi; 53*54b96380SRuslan Bukin struct clkdom *clkdom; 54*54b96380SRuslan Bukin }; 55*54b96380SRuslan Bukin 56*54b96380SRuslan Bukin struct scmi_clknode_softc { 57*54b96380SRuslan Bukin device_t dev; 58*54b96380SRuslan Bukin int clock_id; 59*54b96380SRuslan Bukin }; 60*54b96380SRuslan Bukin 61*54b96380SRuslan Bukin static int 62*54b96380SRuslan Bukin scmi_clk_get_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t *rate) 63*54b96380SRuslan Bukin { 64*54b96380SRuslan Bukin struct scmi_clk_rate_get_out out; 65*54b96380SRuslan Bukin struct scmi_clk_rate_get_in in; 66*54b96380SRuslan Bukin struct scmi_req req; 67*54b96380SRuslan Bukin int error; 68*54b96380SRuslan Bukin 69*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 70*54b96380SRuslan Bukin req.message_id = SCMI_CLOCK_RATE_GET; 71*54b96380SRuslan Bukin req.in_buf = ∈ 72*54b96380SRuslan Bukin req.in_size = sizeof(struct scmi_clk_rate_get_in); 73*54b96380SRuslan Bukin req.out_buf = &out; 74*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_rate_get_out); 75*54b96380SRuslan Bukin 76*54b96380SRuslan Bukin in.clock_id = clk_id; 77*54b96380SRuslan Bukin 78*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 79*54b96380SRuslan Bukin if (error != 0) 80*54b96380SRuslan Bukin return (error); 81*54b96380SRuslan Bukin 82*54b96380SRuslan Bukin if (out.status != 0) 83*54b96380SRuslan Bukin return (ENXIO); 84*54b96380SRuslan Bukin 85*54b96380SRuslan Bukin *rate = out.rate_lsb | ((uint64_t)out.rate_msb << 32); 86*54b96380SRuslan Bukin 87*54b96380SRuslan Bukin return (0); 88*54b96380SRuslan Bukin } 89*54b96380SRuslan Bukin 90*54b96380SRuslan Bukin static int 91*54b96380SRuslan Bukin scmi_clk_set_rate(struct scmi_clk_softc *sc, int clk_id, uint64_t rate) 92*54b96380SRuslan Bukin { 93*54b96380SRuslan Bukin struct scmi_clk_rate_set_out out; 94*54b96380SRuslan Bukin struct scmi_clk_rate_set_in in; 95*54b96380SRuslan Bukin struct scmi_req req; 96*54b96380SRuslan Bukin int error; 97*54b96380SRuslan Bukin 98*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 99*54b96380SRuslan Bukin req.message_id = SCMI_CLOCK_RATE_SET; 100*54b96380SRuslan Bukin req.in_buf = ∈ 101*54b96380SRuslan Bukin req.in_size = sizeof(struct scmi_clk_rate_set_in); 102*54b96380SRuslan Bukin req.out_buf = &out; 103*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_rate_set_out); 104*54b96380SRuslan Bukin 105*54b96380SRuslan Bukin in.clock_id = clk_id; 106*54b96380SRuslan Bukin in.flags = SCMI_CLK_RATE_ROUND_CLOSEST; 107*54b96380SRuslan Bukin in.rate_lsb = (uint32_t)rate; 108*54b96380SRuslan Bukin in.rate_msb = (uint32_t)(rate >> 32); 109*54b96380SRuslan Bukin 110*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 111*54b96380SRuslan Bukin if (error != 0) 112*54b96380SRuslan Bukin return (error); 113*54b96380SRuslan Bukin 114*54b96380SRuslan Bukin if (out.status != 0) 115*54b96380SRuslan Bukin return (ENXIO); 116*54b96380SRuslan Bukin 117*54b96380SRuslan Bukin return (0); 118*54b96380SRuslan Bukin } 119*54b96380SRuslan Bukin 120*54b96380SRuslan Bukin static int 121*54b96380SRuslan Bukin scmi_clk_gate(struct scmi_clk_softc *sc, int clk_id, int enable) 122*54b96380SRuslan Bukin { 123*54b96380SRuslan Bukin struct scmi_clk_state_out out; 124*54b96380SRuslan Bukin struct scmi_clk_state_in in; 125*54b96380SRuslan Bukin struct scmi_req req; 126*54b96380SRuslan Bukin int error; 127*54b96380SRuslan Bukin 128*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 129*54b96380SRuslan Bukin req.message_id = SCMI_CLOCK_CONFIG_SET; 130*54b96380SRuslan Bukin req.in_buf = ∈ 131*54b96380SRuslan Bukin req.in_size = sizeof(struct scmi_clk_state_in); 132*54b96380SRuslan Bukin req.out_buf = &out; 133*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_state_out); 134*54b96380SRuslan Bukin 135*54b96380SRuslan Bukin in.clock_id = clk_id; 136*54b96380SRuslan Bukin in.attributes = enable; 137*54b96380SRuslan Bukin 138*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 139*54b96380SRuslan Bukin if (error != 0) 140*54b96380SRuslan Bukin return (error); 141*54b96380SRuslan Bukin 142*54b96380SRuslan Bukin if (out.status != 0) 143*54b96380SRuslan Bukin return (ENXIO); 144*54b96380SRuslan Bukin 145*54b96380SRuslan Bukin return (0); 146*54b96380SRuslan Bukin } 147*54b96380SRuslan Bukin 148*54b96380SRuslan Bukin static int 149*54b96380SRuslan Bukin scmi_clknode_init(struct clknode *clk, device_t dev) 150*54b96380SRuslan Bukin { 151*54b96380SRuslan Bukin 152*54b96380SRuslan Bukin clknode_init_parent_idx(clk, 0); 153*54b96380SRuslan Bukin 154*54b96380SRuslan Bukin return (0); 155*54b96380SRuslan Bukin } 156*54b96380SRuslan Bukin 157*54b96380SRuslan Bukin static int 158*54b96380SRuslan Bukin scmi_clknode_recalc_freq(struct clknode *clk, uint64_t *freq) 159*54b96380SRuslan Bukin { 160*54b96380SRuslan Bukin 161*54b96380SRuslan Bukin return (0); 162*54b96380SRuslan Bukin } 163*54b96380SRuslan Bukin 164*54b96380SRuslan Bukin static int 165*54b96380SRuslan Bukin scmi_clknode_set_freq(struct clknode *clk, uint64_t fin, uint64_t *fout, 166*54b96380SRuslan Bukin int flags, int *stop) 167*54b96380SRuslan Bukin { 168*54b96380SRuslan Bukin struct scmi_clknode_softc *clk_sc; 169*54b96380SRuslan Bukin struct scmi_clk_softc *sc; 170*54b96380SRuslan Bukin 171*54b96380SRuslan Bukin clk_sc = clknode_get_softc(clk); 172*54b96380SRuslan Bukin sc = device_get_softc(clk_sc->dev); 173*54b96380SRuslan Bukin 174*54b96380SRuslan Bukin dprintf("%s: %ld\n", __func__, *fout); 175*54b96380SRuslan Bukin 176*54b96380SRuslan Bukin scmi_clk_set_rate(sc, clk_sc->clock_id, *fout); 177*54b96380SRuslan Bukin 178*54b96380SRuslan Bukin *stop = 1; 179*54b96380SRuslan Bukin 180*54b96380SRuslan Bukin return (0); 181*54b96380SRuslan Bukin } 182*54b96380SRuslan Bukin 183*54b96380SRuslan Bukin static clknode_method_t scmi_clknode_methods[] = { 184*54b96380SRuslan Bukin /* Device interface */ 185*54b96380SRuslan Bukin CLKNODEMETHOD(clknode_init, scmi_clknode_init), 186*54b96380SRuslan Bukin CLKNODEMETHOD(clknode_recalc_freq, scmi_clknode_recalc_freq), 187*54b96380SRuslan Bukin CLKNODEMETHOD(clknode_set_freq, scmi_clknode_set_freq), 188*54b96380SRuslan Bukin CLKNODEMETHOD_END 189*54b96380SRuslan Bukin }; 190*54b96380SRuslan Bukin 191*54b96380SRuslan Bukin DEFINE_CLASS_1(scmi_clknode, scmi_clknode_class, scmi_clknode_methods, 192*54b96380SRuslan Bukin sizeof(struct scmi_clknode_softc), clknode_class); 193*54b96380SRuslan Bukin 194*54b96380SRuslan Bukin static int 195*54b96380SRuslan Bukin scmi_clk_add_node(struct scmi_clk_softc *sc, int index, char *clock_name) 196*54b96380SRuslan Bukin { 197*54b96380SRuslan Bukin struct scmi_clknode_softc *clk_sc; 198*54b96380SRuslan Bukin struct clknode_init_def def; 199*54b96380SRuslan Bukin struct clknode *clk; 200*54b96380SRuslan Bukin 201*54b96380SRuslan Bukin memset(&def, 0, sizeof(def)); 202*54b96380SRuslan Bukin def.id = index; 203*54b96380SRuslan Bukin def.name = clock_name; 204*54b96380SRuslan Bukin def.parent_names = NULL; 205*54b96380SRuslan Bukin def.parent_cnt = 0; 206*54b96380SRuslan Bukin 207*54b96380SRuslan Bukin clk = clknode_create(sc->clkdom, &scmi_clknode_class, &def); 208*54b96380SRuslan Bukin if (clk == NULL) { 209*54b96380SRuslan Bukin device_printf(sc->dev, "Cannot create clknode.\n"); 210*54b96380SRuslan Bukin return (ENXIO); 211*54b96380SRuslan Bukin } 212*54b96380SRuslan Bukin 213*54b96380SRuslan Bukin clk_sc = clknode_get_softc(clk); 214*54b96380SRuslan Bukin clk_sc->dev = sc->dev; 215*54b96380SRuslan Bukin clk_sc->clock_id = index; 216*54b96380SRuslan Bukin 217*54b96380SRuslan Bukin if (clknode_register(sc->clkdom, clk) == NULL) { 218*54b96380SRuslan Bukin device_printf(sc->dev, "Could not register clock '%s'.\n", 219*54b96380SRuslan Bukin def.name); 220*54b96380SRuslan Bukin return (ENXIO); 221*54b96380SRuslan Bukin } 222*54b96380SRuslan Bukin 223*54b96380SRuslan Bukin device_printf(sc->dev, "Clock '%s' registered.\n", def.name); 224*54b96380SRuslan Bukin 225*54b96380SRuslan Bukin return (0); 226*54b96380SRuslan Bukin } 227*54b96380SRuslan Bukin 228*54b96380SRuslan Bukin static int 229*54b96380SRuslan Bukin scmi_clk_get_name(struct scmi_clk_softc *sc, int index, char **result) 230*54b96380SRuslan Bukin { 231*54b96380SRuslan Bukin struct scmi_clk_name_get_out out; 232*54b96380SRuslan Bukin struct scmi_clk_name_get_in in; 233*54b96380SRuslan Bukin struct scmi_req req; 234*54b96380SRuslan Bukin char *clock_name; 235*54b96380SRuslan Bukin int error; 236*54b96380SRuslan Bukin 237*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 238*54b96380SRuslan Bukin req.message_id = SCMI_CLOCK_NAME_GET; 239*54b96380SRuslan Bukin req.in_buf = ∈ 240*54b96380SRuslan Bukin req.in_size = sizeof(struct scmi_clk_name_get_in); 241*54b96380SRuslan Bukin req.out_buf = &out; 242*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_name_get_out); 243*54b96380SRuslan Bukin 244*54b96380SRuslan Bukin in.clock_id = index; 245*54b96380SRuslan Bukin 246*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 247*54b96380SRuslan Bukin if (error != 0) 248*54b96380SRuslan Bukin return (error); 249*54b96380SRuslan Bukin 250*54b96380SRuslan Bukin if (out.status != 0) 251*54b96380SRuslan Bukin return (ENXIO); 252*54b96380SRuslan Bukin 253*54b96380SRuslan Bukin clock_name = malloc(sizeof(out.name), M_DEVBUF, M_WAITOK); 254*54b96380SRuslan Bukin strncpy(clock_name, out.name, sizeof(out.name)); 255*54b96380SRuslan Bukin 256*54b96380SRuslan Bukin *result = clock_name; 257*54b96380SRuslan Bukin 258*54b96380SRuslan Bukin return (0); 259*54b96380SRuslan Bukin } 260*54b96380SRuslan Bukin 261*54b96380SRuslan Bukin static int 262*54b96380SRuslan Bukin scmi_clk_attrs(struct scmi_clk_softc *sc, int index) 263*54b96380SRuslan Bukin { 264*54b96380SRuslan Bukin struct scmi_clk_attrs_out out; 265*54b96380SRuslan Bukin struct scmi_clk_attrs_in in; 266*54b96380SRuslan Bukin struct scmi_req req; 267*54b96380SRuslan Bukin int error; 268*54b96380SRuslan Bukin char *clock_name; 269*54b96380SRuslan Bukin 270*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 271*54b96380SRuslan Bukin req.message_id = SCMI_CLOCK_ATTRIBUTES; 272*54b96380SRuslan Bukin req.in_buf = ∈ 273*54b96380SRuslan Bukin req.in_size = sizeof(struct scmi_clk_attrs_in); 274*54b96380SRuslan Bukin req.out_buf = &out; 275*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_attrs_out); 276*54b96380SRuslan Bukin 277*54b96380SRuslan Bukin in.clock_id = index; 278*54b96380SRuslan Bukin 279*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 280*54b96380SRuslan Bukin if (error != 0) 281*54b96380SRuslan Bukin return (error); 282*54b96380SRuslan Bukin 283*54b96380SRuslan Bukin if (out.status != 0) 284*54b96380SRuslan Bukin return (ENXIO); 285*54b96380SRuslan Bukin 286*54b96380SRuslan Bukin if (out.attributes & CLK_ATTRS_EXT_CLK_NAME) { 287*54b96380SRuslan Bukin error = scmi_clk_get_name(sc, index, &clock_name); 288*54b96380SRuslan Bukin if (error) 289*54b96380SRuslan Bukin return (error); 290*54b96380SRuslan Bukin } else { 291*54b96380SRuslan Bukin clock_name = malloc(sizeof(out.clock_name), M_DEVBUF, M_WAITOK); 292*54b96380SRuslan Bukin strncpy(clock_name, out.clock_name, sizeof(out.clock_name)); 293*54b96380SRuslan Bukin } 294*54b96380SRuslan Bukin 295*54b96380SRuslan Bukin error = scmi_clk_add_node(sc, index, clock_name); 296*54b96380SRuslan Bukin 297*54b96380SRuslan Bukin return (error); 298*54b96380SRuslan Bukin } 299*54b96380SRuslan Bukin 300*54b96380SRuslan Bukin static int 301*54b96380SRuslan Bukin scmi_clk_discover(struct scmi_clk_softc *sc) 302*54b96380SRuslan Bukin { 303*54b96380SRuslan Bukin struct scmi_clk_protocol_attrs_out out; 304*54b96380SRuslan Bukin struct scmi_req req; 305*54b96380SRuslan Bukin int nclocks; 306*54b96380SRuslan Bukin int failing; 307*54b96380SRuslan Bukin int error; 308*54b96380SRuslan Bukin int i; 309*54b96380SRuslan Bukin 310*54b96380SRuslan Bukin req.protocol_id = SCMI_PROTOCOL_ID_CLOCK; 311*54b96380SRuslan Bukin req.message_id = SCMI_PROTOCOL_ATTRIBUTES; 312*54b96380SRuslan Bukin req.in_buf = NULL; 313*54b96380SRuslan Bukin req.in_size = 0; 314*54b96380SRuslan Bukin req.out_buf = &out; 315*54b96380SRuslan Bukin req.out_size = sizeof(struct scmi_clk_protocol_attrs_out); 316*54b96380SRuslan Bukin 317*54b96380SRuslan Bukin error = scmi_request(sc->scmi, &req); 318*54b96380SRuslan Bukin if (error != 0) 319*54b96380SRuslan Bukin return (error); 320*54b96380SRuslan Bukin 321*54b96380SRuslan Bukin if (out.status != 0) 322*54b96380SRuslan Bukin return (ENXIO); 323*54b96380SRuslan Bukin 324*54b96380SRuslan Bukin nclocks = (out.attributes & CLK_ATTRS_NCLOCKS_M) >> 325*54b96380SRuslan Bukin CLK_ATTRS_NCLOCKS_S; 326*54b96380SRuslan Bukin 327*54b96380SRuslan Bukin device_printf(sc->dev, "Found %d clocks.\n", nclocks); 328*54b96380SRuslan Bukin 329*54b96380SRuslan Bukin failing = 0; 330*54b96380SRuslan Bukin 331*54b96380SRuslan Bukin for (i = 0; i < nclocks; i++) { 332*54b96380SRuslan Bukin error = scmi_clk_attrs(sc, i); 333*54b96380SRuslan Bukin if (error) { 334*54b96380SRuslan Bukin device_printf(sc->dev, 335*54b96380SRuslan Bukin "Could not process clock index %d.\n", i); 336*54b96380SRuslan Bukin failing++; 337*54b96380SRuslan Bukin } 338*54b96380SRuslan Bukin } 339*54b96380SRuslan Bukin 340*54b96380SRuslan Bukin if (failing == nclocks) 341*54b96380SRuslan Bukin return (ENXIO); 342*54b96380SRuslan Bukin 343*54b96380SRuslan Bukin return (0); 344*54b96380SRuslan Bukin } 345*54b96380SRuslan Bukin 346*54b96380SRuslan Bukin static int 347*54b96380SRuslan Bukin scmi_clk_init(struct scmi_clk_softc *sc) 348*54b96380SRuslan Bukin { 349*54b96380SRuslan Bukin int error; 350*54b96380SRuslan Bukin 351*54b96380SRuslan Bukin /* Create clock domain */ 352*54b96380SRuslan Bukin sc->clkdom = clkdom_create(sc->dev); 353*54b96380SRuslan Bukin if (sc->clkdom == NULL) 354*54b96380SRuslan Bukin return (ENXIO); 355*54b96380SRuslan Bukin 356*54b96380SRuslan Bukin error = scmi_clk_discover(sc); 357*54b96380SRuslan Bukin if (error) { 358*54b96380SRuslan Bukin device_printf(sc->dev, "Could not discover clocks.\n"); 359*54b96380SRuslan Bukin return (ENXIO); 360*54b96380SRuslan Bukin } 361*54b96380SRuslan Bukin 362*54b96380SRuslan Bukin error = clkdom_finit(sc->clkdom); 363*54b96380SRuslan Bukin if (error) { 364*54b96380SRuslan Bukin device_printf(sc->dev, "Failed to init clock domain.\n"); 365*54b96380SRuslan Bukin return (ENXIO); 366*54b96380SRuslan Bukin } 367*54b96380SRuslan Bukin 368*54b96380SRuslan Bukin return (0); 369*54b96380SRuslan Bukin } 370*54b96380SRuslan Bukin 371*54b96380SRuslan Bukin static int 372*54b96380SRuslan Bukin scmi_clk_probe(device_t dev) 373*54b96380SRuslan Bukin { 374*54b96380SRuslan Bukin phandle_t node; 375*54b96380SRuslan Bukin uint32_t reg; 376*54b96380SRuslan Bukin int error; 377*54b96380SRuslan Bukin 378*54b96380SRuslan Bukin node = ofw_bus_get_node(dev); 379*54b96380SRuslan Bukin 380*54b96380SRuslan Bukin error = OF_getencprop(node, "reg", ®, sizeof(uint32_t)); 381*54b96380SRuslan Bukin if (error < 0) 382*54b96380SRuslan Bukin return (ENXIO); 383*54b96380SRuslan Bukin 384*54b96380SRuslan Bukin if (reg != SCMI_PROTOCOL_ID_CLOCK) 385*54b96380SRuslan Bukin return (ENXIO); 386*54b96380SRuslan Bukin 387*54b96380SRuslan Bukin device_set_desc(dev, "SCMI Clock Management Unit"); 388*54b96380SRuslan Bukin 389*54b96380SRuslan Bukin return (BUS_PROBE_DEFAULT); 390*54b96380SRuslan Bukin } 391*54b96380SRuslan Bukin 392*54b96380SRuslan Bukin static int 393*54b96380SRuslan Bukin scmi_clk_attach(device_t dev) 394*54b96380SRuslan Bukin { 395*54b96380SRuslan Bukin struct scmi_clk_softc *sc; 396*54b96380SRuslan Bukin phandle_t node; 397*54b96380SRuslan Bukin 398*54b96380SRuslan Bukin sc = device_get_softc(dev); 399*54b96380SRuslan Bukin sc->dev = dev; 400*54b96380SRuslan Bukin sc->scmi = device_get_parent(dev); 401*54b96380SRuslan Bukin 402*54b96380SRuslan Bukin node = ofw_bus_get_node(sc->dev); 403*54b96380SRuslan Bukin 404*54b96380SRuslan Bukin OF_device_register_xref(OF_xref_from_node(node), sc->dev); 405*54b96380SRuslan Bukin 406*54b96380SRuslan Bukin scmi_clk_init(sc); 407*54b96380SRuslan Bukin 408*54b96380SRuslan Bukin return (0); 409*54b96380SRuslan Bukin } 410*54b96380SRuslan Bukin 411*54b96380SRuslan Bukin static int 412*54b96380SRuslan Bukin scmi_clk_detach(device_t dev) 413*54b96380SRuslan Bukin { 414*54b96380SRuslan Bukin 415*54b96380SRuslan Bukin return (0); 416*54b96380SRuslan Bukin } 417*54b96380SRuslan Bukin 418*54b96380SRuslan Bukin static device_method_t scmi_clk_methods[] = { 419*54b96380SRuslan Bukin /* Device interface */ 420*54b96380SRuslan Bukin DEVMETHOD(device_probe, scmi_clk_probe), 421*54b96380SRuslan Bukin DEVMETHOD(device_attach, scmi_clk_attach), 422*54b96380SRuslan Bukin DEVMETHOD(device_detach, scmi_clk_detach), 423*54b96380SRuslan Bukin DEVMETHOD_END 424*54b96380SRuslan Bukin }; 425*54b96380SRuslan Bukin 426*54b96380SRuslan Bukin static driver_t scmi_clk_driver = { 427*54b96380SRuslan Bukin "scmi_clk", 428*54b96380SRuslan Bukin scmi_clk_methods, 429*54b96380SRuslan Bukin sizeof(struct scmi_clk_softc), 430*54b96380SRuslan Bukin }; 431*54b96380SRuslan Bukin 432*54b96380SRuslan Bukin EARLY_DRIVER_MODULE(scmi_clk, scmi, scmi_clk_driver, 0, 0, 433*54b96380SRuslan Bukin BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 434*54b96380SRuslan Bukin MODULE_VERSION(scmi_clk, 1); 435