diff options
author | David S. Miller <davem@davemloft.net> | 2008-08-25 00:32:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-08-25 00:32:42 -0400 |
commit | b28422e32b9127ab4178ce05a419069db3d11d19 (patch) | |
tree | d787c136b42f1cb82cc10a2144f1a4db7a8d2c95 /arch | |
parent | e04180882faf69e896a8131ff3137788dd08b8d3 (diff) |
sparc64: Convert UltraSPARC-III memory controller driver to OF driver probing.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc64/kernel/chmc.c | 119 |
1 files changed, 78 insertions, 41 deletions
diff --git a/arch/sparc64/kernel/chmc.c b/arch/sparc64/kernel/chmc.c index 6d4f02e8a4cf..b9cd736a11f7 100644 --- a/arch/sparc64/kernel/chmc.c +++ b/arch/sparc64/kernel/chmc.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* memctrlr.c: Driver for UltraSPARC-III memory controller. | 1 | /* chmc.c: Driver for UltraSPARC-III memory controller. |
2 | * | 2 | * |
3 | * Copyright (C) 2001, 2007 David S. Miller (davem@davemloft.net) | 3 | * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net) |
4 | */ | 4 | */ |
5 | 5 | ||
6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
@@ -13,13 +13,25 @@ | |||
13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
16 | #include <asm/spitfire.h> | 18 | #include <asm/spitfire.h> |
17 | #include <asm/chmctrl.h> | 19 | #include <asm/chmctrl.h> |
18 | #include <asm/cpudata.h> | 20 | #include <asm/cpudata.h> |
19 | #include <asm/oplib.h> | 21 | #include <asm/oplib.h> |
20 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/head.h> | ||
21 | #include <asm/io.h> | 24 | #include <asm/io.h> |
22 | 25 | ||
26 | #define DRV_MODULE_NAME "chmc" | ||
27 | #define PFX DRV_MODULE_NAME ": " | ||
28 | #define DRV_MODULE_VERSION "0.2" | ||
29 | |||
30 | MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); | ||
31 | MODULE_DESCRIPTION("UltraSPARC-III memory controller driver"); | ||
32 | MODULE_LICENSE("GPL"); | ||
33 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
34 | |||
23 | #define CHMCTRL_NDGRPS 2 | 35 | #define CHMCTRL_NDGRPS 2 |
24 | #define CHMCTRL_NDIMMS 4 | 36 | #define CHMCTRL_NDIMMS 4 |
25 | 37 | ||
@@ -343,16 +355,25 @@ static void fetch_decode_regs(struct mctrl_info *mp) | |||
343 | read_mcreg(mp, CHMCTRL_DECODE4)); | 355 | read_mcreg(mp, CHMCTRL_DECODE4)); |
344 | } | 356 | } |
345 | 357 | ||
346 | static int init_one_mctrl(struct device_node *dp) | 358 | static int __devinit chmc_probe(struct of_device *op, |
359 | const struct of_device_id *match) | ||
347 | { | 360 | { |
348 | struct mctrl_info *mp = kzalloc(sizeof(*mp), GFP_KERNEL); | 361 | struct device_node *dp = op->node; |
349 | int portid = of_getintprop_default(dp, "portid", -1); | 362 | struct mctrl_info *mp; |
350 | const struct linux_prom64_registers *regs; | 363 | unsigned long ver; |
351 | const void *pval; | 364 | const void *pval; |
352 | int len; | 365 | int len, portid; |
366 | |||
367 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | ||
368 | if ((ver >> 32UL) == __JALAPENO_ID || | ||
369 | (ver >> 32UL) == __SERRANO_ID) | ||
370 | return -ENODEV; | ||
353 | 371 | ||
372 | mp = kzalloc(sizeof(*mp), GFP_KERNEL); | ||
354 | if (!mp) | 373 | if (!mp) |
355 | return -1; | 374 | return -ENOMEM; |
375 | |||
376 | portid = of_getintprop_default(dp, "portid", -1); | ||
356 | if (portid == -1) | 377 | if (portid == -1) |
357 | goto fail; | 378 | goto fail; |
358 | 379 | ||
@@ -362,18 +383,19 @@ static int init_one_mctrl(struct device_node *dp) | |||
362 | if (!pval) | 383 | if (!pval) |
363 | mp->layout_size = 0; | 384 | mp->layout_size = 0; |
364 | else { | 385 | else { |
365 | if (mp->layout_size > sizeof(mp->layout_prop)) | 386 | if (mp->layout_size > sizeof(mp->layout_prop)) { |
387 | printk(KERN_ERR PFX "Unexpected memory-layout property " | ||
388 | "size %d.\n", mp->layout_size); | ||
366 | goto fail; | 389 | goto fail; |
390 | } | ||
367 | memcpy(&mp->layout_prop, pval, len); | 391 | memcpy(&mp->layout_prop, pval, len); |
368 | } | 392 | } |
369 | 393 | ||
370 | regs = of_get_property(dp, "reg", NULL); | 394 | mp->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc"); |
371 | if (!regs || regs->reg_size != 0x48) | 395 | if (!mp->regs) { |
372 | goto fail; | 396 | printk(KERN_ERR PFX "Could not map registers.\n"); |
373 | |||
374 | mp->regs = ioremap(regs->phys_addr, regs->reg_size); | ||
375 | if (mp->regs == NULL) | ||
376 | goto fail; | 397 | goto fail; |
398 | } | ||
377 | 399 | ||
378 | if (mp->layout_size != 0UL) { | 400 | if (mp->layout_size != 0UL) { |
379 | mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); | 401 | mp->timing_control1 = read_mcreg(mp, CHMCTRL_TCTRL1); |
@@ -388,54 +410,69 @@ static int init_one_mctrl(struct device_node *dp) | |||
388 | list_add(&mp->list, &mctrl_list); | 410 | list_add(&mp->list, &mctrl_list); |
389 | 411 | ||
390 | /* Report the device. */ | 412 | /* Report the device. */ |
391 | printk(KERN_INFO "%s: US3 memory controller at %p [%s]\n", | 413 | printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n", |
392 | dp->full_name, | 414 | dp->full_name, |
393 | mp->regs, (mp->layout_size ? "ACTIVE" : "INACTIVE")); | 415 | (mp->layout_size ? "ACTIVE" : "INACTIVE")); |
416 | |||
417 | dev_set_drvdata(&op->dev, mp); | ||
394 | 418 | ||
395 | return 0; | 419 | return 0; |
396 | 420 | ||
397 | fail: | 421 | fail: |
398 | if (mp) { | 422 | if (mp) { |
399 | if (mp->regs != NULL) | 423 | if (mp->regs != NULL) |
400 | iounmap(mp->regs); | 424 | of_iounmap(&op->resource[0], mp->regs, 0x48); |
401 | kfree(mp); | 425 | kfree(mp); |
402 | } | 426 | } |
403 | return -1; | 427 | return -1; |
404 | } | 428 | } |
405 | 429 | ||
406 | static int __init chmc_init(void) | 430 | static int __devexit chmc_remove(struct of_device *op) |
407 | { | 431 | { |
408 | struct device_node *dp; | 432 | struct mctrl_info *mp = dev_get_drvdata(&op->dev); |
409 | 433 | ||
410 | /* This driver is only for cheetah platforms. */ | 434 | if (mp) { |
411 | if (tlb_type != cheetah && tlb_type != cheetah_plus) | 435 | list_del(&mp->list); |
412 | return -ENODEV; | 436 | of_iounmap(&op->resource[0], mp->regs, 0x48); |
437 | kfree(mp); | ||
438 | } | ||
439 | return 0; | ||
440 | } | ||
413 | 441 | ||
414 | for_each_node_by_name(dp, "memory-controller") | 442 | static struct of_device_id chmc_match[] = { |
415 | init_one_mctrl(dp); | 443 | { |
444 | .name = "memory-controller", | ||
445 | }, | ||
446 | {}, | ||
447 | }; | ||
448 | MODULE_DEVICE_TABLE(of, chmc_match); | ||
416 | 449 | ||
417 | for_each_node_by_name(dp, "mc-us3") | 450 | static struct of_platform_driver chmc_driver = { |
418 | init_one_mctrl(dp); | 451 | .name = "chmc", |
452 | .match_table = chmc_match, | ||
453 | .probe = chmc_probe, | ||
454 | .remove = __devexit_p(chmc_remove), | ||
455 | }; | ||
419 | 456 | ||
420 | return 0; | 457 | static inline bool chmc_platform(void) |
458 | { | ||
459 | if (tlb_type == cheetah || tlb_type == cheetah_plus) | ||
460 | return true; | ||
461 | return false; | ||
421 | } | 462 | } |
422 | 463 | ||
423 | static void __exit chmc_cleanup(void) | 464 | static int __init chmc_init(void) |
424 | { | 465 | { |
425 | struct list_head *head = &mctrl_list; | 466 | if (!chmc_platform()) |
426 | struct list_head *tmp = head->next; | 467 | return -ENODEV; |
427 | 468 | ||
428 | for (;;) { | 469 | return of_register_driver(&chmc_driver, &of_bus_type); |
429 | struct mctrl_info *p = | 470 | } |
430 | list_entry(tmp, struct mctrl_info, list); | ||
431 | if (tmp == head) | ||
432 | break; | ||
433 | tmp = tmp->next; | ||
434 | 471 | ||
435 | list_del(&p->list); | 472 | static void __exit chmc_cleanup(void) |
436 | iounmap(p->regs); | 473 | { |
437 | kfree(p); | 474 | if (chmc_platform()) |
438 | } | 475 | of_unregister_driver(&chmc_driver); |
439 | } | 476 | } |
440 | 477 | ||
441 | module_init(chmc_init); | 478 | module_init(chmc_init); |