1/*- 2 * Copyright 2015 John Wehle <john@feith.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * Amlogic aml8726 multiprocessor support. 29 * 30 * Some processors require powering on which involves poking registers 31 * on the aobus and cbus ... it's expected that these locations are set 32 * in stone. 33 * 34 * Locking is not used as these routines should only be called by the BP 35 * during startup and should complete prior to the APs being released (the 36 * issue being to ensure that a register such as AML_SOC_CPU_CLK_CNTL_REG 37 * is not concurrently modified). 38 */ 39 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD: releng/11.0/sys/arm/amlogic/aml8726/aml8726_mp.c 296100 2016-02-26 16:04:47Z andrew $"); 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/bus.h> 45#include <sys/kernel.h> 46#include <sys/module.h> 47#include <sys/lock.h> 48#include <sys/mutex.h> 49#include <sys/resource.h> 50#include <sys/rman.h> 51#include <sys/smp.h> 52 53#include <vm/vm.h> 54#include <vm/pmap.h> 55 56#include <machine/cpu.h> 57#include <machine/bus.h> 58#include <machine/smp.h> 59#include <machine/fdt.h> 60#include <machine/intr.h> 61 62#include <dev/fdt/fdt_common.h> 63#include <dev/ofw/ofw_bus.h> 64#include <dev/ofw/ofw_bus_subr.h> 65 66#include <arm/amlogic/aml8726/aml8726_soc.h> 67 68static const char *scu_compatible[] = { 69 "arm,cortex-a5-scu", 70 "arm,cortex-a9-scu", 71 NULL 72}; 73 74static const char *scu_errata_764369[] = { 75 "arm,cortex-a9-scu", 76 NULL 77}; 78 79static const char *cpucfg_compatible[] = { 80 "amlogic,aml8726-cpuconfig", 81 NULL 82}; 83 84static struct { 85 boolean_t errata_764369; 86 u_long scu_size; 87 struct resource scu_res; 88 u_long cpucfg_size; 89 struct resource cpucfg_res; 90 struct resource aobus_res; 91 struct resource cbus_res; 92} aml8726_smp; 93 94#define AML_SCU_CONTROL_REG 0 95#define AML_SCU_CONTROL_ENABLE 1 96#define AML_SCU_CONFIG_REG 4 97#define AML_SCU_CONFIG_NCPU_MASK 0x3 98#define AML_SCU_CPU_PWR_STATUS_REG 8 99#define AML_SCU_CPU_PWR_STATUS_CPU3_MASK (3 << 24) 100#define AML_SCU_CPU_PWR_STATUS_CPU2_MASK (3 << 16) 101#define AML_SCU_CPU_PWR_STATUS_CPU1_MASK (3 << 8) 102#define AML_SCU_CPU_PWR_STATUS_CPU0_MASK 3 103#define AML_SCU_INV_TAGS_REG 12 104#define AML_SCU_DIAG_CONTROL_REG 48 105#define AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT 1 106 107#define AML_CPUCONF_CONTROL_REG 0 108#define AML_CPUCONF_CPU1_ADDR_REG 4 109#define AML_CPUCONF_CPU2_ADDR_REG 8 110#define AML_CPUCONF_CPU3_ADDR_REG 12 111 112/* aobus */ 113 114#define AML_M8_CPU_PWR_CNTL0_REG 0xe0 115#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU3_MASK (3 << 22) 116#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU2_MASK (3 << 20) 117#define AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK (3 << 18) 118 119#define AML_M8_CPU_PWR_CNTL0_ISO_CPU3 (1 << 3) 120#define AML_M8_CPU_PWR_CNTL0_ISO_CPU2 (1 << 2) 121#define AML_M8_CPU_PWR_CNTL0_ISO_CPU1 (1 << 1) 122 123#define AML_M8_CPU_PWR_CNTL1_REG 0xe4 124#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU3 (1 << 19) 125#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU2 (1 << 18) 126#define AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 (1 << 17) 127 128#define AML_M8_CPU_PWR_CNTL1_MODE_CPU3_MASK (3 << 8) 129#define AML_M8_CPU_PWR_CNTL1_MODE_CPU2_MASK (3 << 6) 130#define AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK (3 << 4) 131 132#define AML_M8B_CPU_PWR_MEM_PD0_REG 0xf4 133#define AML_M8B_CPU_PWR_MEM_PD0_CPU3 (0xf << 20) 134#define AML_M8B_CPU_PWR_MEM_PD0_CPU2 (0xf << 24) 135#define AML_M8B_CPU_PWR_MEM_PD0_CPU1 (0xf << 28) 136 137/* cbus */ 138 139#define AML_SOC_CPU_CLK_CNTL_REG 0x419c 140#define AML_M8_CPU_CLK_CNTL_RESET_CPU3 (1 << 27) 141#define AML_M8_CPU_CLK_CNTL_RESET_CPU2 (1 << 26) 142#define AML_M8_CPU_CLK_CNTL_RESET_CPU1 (1 << 25) 143 144#define SCU_WRITE_4(reg, value) bus_write_4(&aml8726_smp.scu_res, \ 145 (reg), (value)) 146#define SCU_READ_4(reg) bus_read_4(&aml8726_smp.scu_res, (reg)) 147#define SCU_BARRIER(reg) bus_barrier(&aml8726_smp.scu_res, \ 148 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 149 150#define CPUCONF_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cpucfg_res, \ 151 (reg), (value)) 152#define CPUCONF_READ_4(reg) bus_read_4(&aml8726_smp.cpucfg_res, \ 153 (reg)) 154#define CPUCONF_BARRIER(reg) bus_barrier(&aml8726_smp.cpucfg_res, \ 155 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 156 157#define AOBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.aobus_res, \ 158 (reg), (value)) 159#define AOBUS_READ_4(reg) bus_read_4(&aml8726_smp.aobus_res, \ 160 (reg)) 161#define AOBUS_BARRIER(reg) bus_barrier(&aml8726_smp.aobus_res, \ 162 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 163 164#define CBUS_WRITE_4(reg, value) bus_write_4(&aml8726_smp.cbus_res, \ 165 (reg), (value)) 166#define CBUS_READ_4(reg) bus_read_4(&aml8726_smp.cbus_res, \ 167 (reg)) 168#define CBUS_BARRIER(reg) bus_barrier(&aml8726_smp.cbus_res, \ 169 (reg), 4, (BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)) 170 171static phandle_t 172find_node_for_device(const char *device, const char **compatible) 173{ 174 int i; 175 phandle_t node; 176 177 /* 178 * Try to access the node directly i.e. through /aliases/. 179 */ 180 181 if ((node = OF_finddevice(device)) != 0) 182 for (i = 0; compatible[i]; i++) 183 if (fdt_is_compatible_strict(node, compatible[i])) 184 return node; 185 186 /* 187 * Find the node the long way. 188 */ 189 190 for (i = 0; compatible[i]; i++) { 191 if ((node = OF_finddevice("/soc")) == 0) 192 return (0); 193 194 if ((node = fdt_find_compatible(node, compatible[i], 1)) != 0) 195 return node; 196 } 197 198 return (0); 199} 200 201 202static int 203alloc_resource_for_node(phandle_t node, struct resource *res, u_long *size) 204{ 205 int err; 206 u_long pbase, psize; 207 u_long start; 208 209 if ((err = fdt_get_range(OF_parent(node), 0, &pbase, &psize)) != 0 || 210 (err = fdt_regsize(node, &start, size)) != 0) 211 return (err); 212 213 start += pbase; 214 215 memset(res, 0, sizeof(*res)); 216 217 res->r_bustag = fdtbus_bs_tag; 218 219 err = bus_space_map(res->r_bustag, start, *size, 0, &res->r_bushandle); 220 221 return (err); 222} 223 224 225static void 226power_on_cpu(int cpu) 227{ 228 uint32_t scpsr; 229 uint32_t value; 230 231 if (cpu <= 0) 232 return; 233 234 /* 235 * Power on the CPU if the intricate details are known, otherwise 236 * just hope for the best (it may have already be powered on by 237 * the hardware / firmware). 238 */ 239 240 switch (aml8726_soc_hw_rev) { 241 case AML_SOC_HW_REV_M8: 242 case AML_SOC_HW_REV_M8B: 243 /* 244 * Set the SCU power status for the CPU to normal mode. 245 */ 246 scpsr = SCU_READ_4(AML_SCU_CPU_PWR_STATUS_REG); 247 scpsr &= ~(AML_SCU_CPU_PWR_STATUS_CPU1_MASK << ((cpu - 1) * 8)); 248 SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 249 SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 250 251 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 252 /* 253 * Reset may cause the current power status from the 254 * actual CPU to be written to the SCU (over-writing 255 * the value we've just written) so set it to normal 256 * mode as well. 257 */ 258 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 259 value &= ~(AML_M8B_CPU_PWR_CNTL0_MODE_CPU1_MASK << 260 ((cpu - 1) * 2)); 261 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 262 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 263 } 264 265 DELAY(5); 266 267 /* 268 * Assert reset. 269 */ 270 value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 271 value |= AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1); 272 CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 273 CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 274 275 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 276 /* 277 * Release RAM pull-down. 278 */ 279 value = AOBUS_READ_4(AML_M8B_CPU_PWR_MEM_PD0_REG); 280 value &= ~((uint32_t)AML_M8B_CPU_PWR_MEM_PD0_CPU1 >> 281 ((cpu - 1) * 4)); 282 AOBUS_WRITE_4(AML_M8B_CPU_PWR_MEM_PD0_REG, value); 283 AOBUS_BARRIER(AML_M8B_CPU_PWR_MEM_PD0_REG); 284 } 285 286 /* 287 * Power on CPU. 288 */ 289 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 290 value &= ~(AML_M8_CPU_PWR_CNTL1_MODE_CPU1_MASK << 291 ((cpu - 1) * 2)); 292 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL1_REG, value); 293 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL1_REG); 294 295 DELAY(10); 296 297 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 298 /* 299 * Wait for power on confirmation. 300 */ 301 for ( ; ; ) { 302 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL1_REG); 303 value &= AML_M8B_CPU_PWR_CNTL1_PWR_CPU1 << 304 (cpu - 1); 305 if (value) 306 break; 307 DELAY(10); 308 } 309 } 310 311 /* 312 * Release peripheral clamp. 313 */ 314 value = AOBUS_READ_4(AML_M8_CPU_PWR_CNTL0_REG); 315 value &= ~(AML_M8_CPU_PWR_CNTL0_ISO_CPU1 << (cpu - 1)); 316 AOBUS_WRITE_4(AML_M8_CPU_PWR_CNTL0_REG, value); 317 AOBUS_BARRIER(AML_M8_CPU_PWR_CNTL0_REG); 318 319 /* 320 * Release reset. 321 */ 322 value = CBUS_READ_4(AML_SOC_CPU_CLK_CNTL_REG); 323 value &= ~(AML_M8_CPU_CLK_CNTL_RESET_CPU1 << (cpu - 1)); 324 CBUS_WRITE_4(AML_SOC_CPU_CLK_CNTL_REG, value); 325 CBUS_BARRIER(AML_SOC_CPU_CLK_CNTL_REG); 326 327 if (aml8726_soc_hw_rev == AML_SOC_HW_REV_M8B) { 328 /* 329 * The Amlogic Linux platform code sets the SCU power 330 * status for the CPU again for some reason so we 331 * follow suit (perhaps in case the reset caused 332 * a stale power status from the actual CPU to be 333 * written to the SCU). 334 */ 335 SCU_WRITE_4(AML_SCU_CPU_PWR_STATUS_REG, scpsr); 336 SCU_BARRIER(AML_SCU_CPU_PWR_STATUS_REG); 337 } 338 break; 339 default: 340 break; 341 } 342} 343 344void 345platform_mp_setmaxid(void) 346{ 347 int err; 348 int i; 349 int ncpu; 350 phandle_t cpucfg_node; 351 phandle_t scu_node; 352 uint32_t value; 353 354 if (mp_ncpus != 0) 355 return; 356 357 ncpu = 1; 358 359 /* 360 * Is the hardware necessary for SMP present? 361 */ 362 363 if ((scu_node = find_node_for_device("scu", scu_compatible)) == 0) 364 goto moveon; 365 366 if ((cpucfg_node = find_node_for_device("cpuconfig", 367 cpucfg_compatible)) == 0) 368 goto moveon; 369 370 if (alloc_resource_for_node(scu_node, &aml8726_smp.scu_res, 371 &aml8726_smp.scu_size) != 0) 372 panic("Could not allocate resource for SCU"); 373 374 if (alloc_resource_for_node(cpucfg_node, &aml8726_smp.cpucfg_res, 375 &aml8726_smp.cpucfg_size) != 0) 376 panic("Could not allocate resource for CPUCONFIG"); 377 378 379 /* 380 * Strictly speaking the aobus and cbus may not be required in 381 * order to start an AP (it depends on the processor), however 382 * always mapping them in simplifies the code. 383 */ 384 385 aml8726_smp.aobus_res.r_bustag = fdtbus_bs_tag; 386 387 err = bus_space_map(aml8726_smp.aobus_res.r_bustag, 388 AML_SOC_AOBUS_BASE_ADDR, 0x100000, 389 0, &aml8726_smp.aobus_res.r_bushandle); 390 391 if (err) 392 panic("Could not allocate resource for AOBUS"); 393 394 aml8726_smp.cbus_res.r_bustag = fdtbus_bs_tag; 395 396 err = bus_space_map(aml8726_smp.cbus_res.r_bustag, 397 AML_SOC_CBUS_BASE_ADDR, 0x100000, 398 0, &aml8726_smp.cbus_res.r_bushandle); 399 400 if (err) 401 panic("Could not allocate resource for CBUS"); 402 403 aml8726_smp.errata_764369 = false; 404 for (i = 0; scu_errata_764369[i]; i++) 405 if (fdt_is_compatible_strict(scu_node, scu_errata_764369[i])) { 406 aml8726_smp.errata_764369 = true; 407 break; 408 } 409 410 /* 411 * Read the number of CPUs present. 412 */ 413 value = SCU_READ_4(AML_SCU_CONFIG_REG); 414 ncpu = (value & AML_SCU_CONFIG_NCPU_MASK) + 1; 415 416moveon: 417 mp_ncpus = ncpu; 418 mp_maxid = ncpu - 1; 419} 420 421void 422platform_mp_start_ap(void) 423{ 424 int i; 425 uint32_t reg; 426 uint32_t value; 427 vm_paddr_t paddr; 428 429 if (mp_ncpus < 2) 430 return; 431 432 /* 433 * Invalidate SCU cache tags. The 0x0000ffff constant invalidates 434 * all ways on all cores 0-3. Per the ARM docs, it's harmless to 435 * write to the bits for cores that are not present. 436 */ 437 SCU_WRITE_4(AML_SCU_INV_TAGS_REG, 0x0000ffff); 438 439 if (aml8726_smp.errata_764369) { 440 /* 441 * Erratum ARM/MP: 764369 (problems with cache maintenance). 442 * Setting the "disable-migratory bit" in the undocumented SCU 443 * Diagnostic Control Register helps work around the problem. 444 */ 445 value = SCU_READ_4(AML_SCU_DIAG_CONTROL_REG); 446 value |= AML_SCU_DIAG_CONTROL_DISABLE_MIGBIT; 447 SCU_WRITE_4(AML_SCU_DIAG_CONTROL_REG, value); 448 } 449 450 /* 451 * Enable the SCU, then clean the cache on this core. After these 452 * two operations the cache tag ram in the SCU is coherent with 453 * the contents of the cache on this core. The other cores aren't 454 * running yet so their caches can't contain valid data yet, however 455 * we've initialized their SCU tag ram above, so they will be 456 * coherent from startup. 457 */ 458 value = SCU_READ_4(AML_SCU_CONTROL_REG); 459 value |= AML_SCU_CONTROL_ENABLE; 460 SCU_WRITE_4(AML_SCU_CONTROL_REG, value); 461 SCU_BARRIER(AML_SCU_CONTROL_REG); 462 dcache_wbinv_poc_all(); 463 464 /* Set the boot address and power on each AP. */ 465 paddr = pmap_kextract((vm_offset_t)mpentry); 466 for (i = 1; i < mp_ncpus; i++) { 467 reg = AML_CPUCONF_CPU1_ADDR_REG + ((i - 1) * 4); 468 CPUCONF_WRITE_4(reg, paddr); 469 CPUCONF_BARRIER(reg); 470 471 power_on_cpu(i); 472 } 473 474 /* 475 * Enable the APs. 476 * 477 * The Amlogic Linux platform code sets the lsb for some reason 478 * in addition to the enable bit for each AP so we follow suit 479 * (the lsb may be the enable bit for the BP, though in that case 480 * it should already be set since it's currently running). 481 */ 482 value = CPUCONF_READ_4(AML_CPUCONF_CONTROL_REG); 483 value |= 1; 484 for (i = 1; i < mp_ncpus; i++) 485 value |= (1 << i); 486 CPUCONF_WRITE_4(AML_CPUCONF_CONTROL_REG, value); 487 CPUCONF_BARRIER(AML_CPUCONF_CONTROL_REG); 488 489 /* Wakeup the now enabled APs */ 490 armv7_sev(); 491 492 /* 493 * Free the resources which are not needed after startup. 494 */ 495 bus_space_unmap(aml8726_smp.scu_res.r_bustag, 496 aml8726_smp.scu_res.r_bushandle, 497 aml8726_smp.scu_size); 498 bus_space_unmap(aml8726_smp.cpucfg_res.r_bustag, 499 aml8726_smp.cpucfg_res.r_bushandle, 500 aml8726_smp.cpucfg_size); 501 bus_space_unmap(aml8726_smp.aobus_res.r_bustag, 502 aml8726_smp.aobus_res.r_bushandle, 503 0x100000); 504 bus_space_unmap(aml8726_smp.cbus_res.r_bustag, 505 aml8726_smp.cbus_res.r_bushandle, 506 0x100000); 507 memset(&aml8726_smp, 0, sizeof(aml8726_smp)); 508} 509 510/* 511 * Stub drivers for cosmetic purposes. 512 */ 513struct aml8726_scu_softc { 514 device_t dev; 515}; 516 517static int 518aml8726_scu_probe(device_t dev) 519{ 520 int i; 521 522 for (i = 0; scu_compatible[i]; i++) 523 if (ofw_bus_is_compatible(dev, scu_compatible[i])) 524 break; 525 526 if (!scu_compatible[i]) 527 return (ENXIO); 528 529 device_set_desc(dev, "ARM Snoop Control Unit"); 530 531 return (BUS_PROBE_DEFAULT); 532} 533 534static int 535aml8726_scu_attach(device_t dev) 536{ 537 struct aml8726_scu_softc *sc = device_get_softc(dev); 538 539 sc->dev = dev; 540 541 return (0); 542} 543 544static int 545aml8726_scu_detach(device_t dev) 546{ 547 548 return (0); 549} 550 551static device_method_t aml8726_scu_methods[] = { 552 /* Device interface */ 553 DEVMETHOD(device_probe, aml8726_scu_probe), 554 DEVMETHOD(device_attach, aml8726_scu_attach), 555 DEVMETHOD(device_detach, aml8726_scu_detach), 556 557 DEVMETHOD_END 558}; 559 560static driver_t aml8726_scu_driver = { 561 "scu", 562 aml8726_scu_methods, 563 sizeof(struct aml8726_scu_softc), 564}; 565 566static devclass_t aml8726_scu_devclass; 567 568EARLY_DRIVER_MODULE(scu, simplebus, aml8726_scu_driver, aml8726_scu_devclass, 569 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 570 571struct aml8726_cpucfg_softc { 572 device_t dev; 573}; 574 575static int 576aml8726_cpucfg_probe(device_t dev) 577{ 578 int i; 579 580 for (i = 0; cpucfg_compatible[i]; i++) 581 if (ofw_bus_is_compatible(dev, cpucfg_compatible[i])) 582 break; 583 584 if (!cpucfg_compatible[i]) 585 return (ENXIO); 586 587 device_set_desc(dev, "Amlogic CPU Config"); 588 589 return (BUS_PROBE_DEFAULT); 590} 591 592static int 593aml8726_cpucfg_attach(device_t dev) 594{ 595 struct aml8726_cpucfg_softc *sc = device_get_softc(dev); 596 597 sc->dev = dev; 598 599 return (0); 600} 601 602static int 603aml8726_cpucfg_detach(device_t dev) 604{ 605 606 return (0); 607} 608 609static device_method_t aml8726_cpucfg_methods[] = { 610 /* Device interface */ 611 DEVMETHOD(device_probe, aml8726_cpucfg_probe), 612 DEVMETHOD(device_attach, aml8726_cpucfg_attach), 613 DEVMETHOD(device_detach, aml8726_cpucfg_detach), 614 615 DEVMETHOD_END 616}; 617 618static driver_t aml8726_cpucfg_driver = { 619 "cpuconfig", 620 aml8726_cpucfg_methods, 621 sizeof(struct aml8726_cpucfg_softc), 622}; 623 624static devclass_t aml8726_cpucfg_devclass; 625 626EARLY_DRIVER_MODULE(cpuconfig, simplebus, aml8726_cpucfg_driver, 627 aml8726_cpucfg_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_MIDDLE); 628