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