diff options
| -rw-r--r-- | Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | 36 | ||||
| -rw-r--r-- | arch/arm/common/timer-sp.c | 3 | ||||
| -rw-r--r-- | arch/arm/mach-mvebu/armada-370-xp.c | 4 | ||||
| -rw-r--r-- | drivers/clocksource/em_sti.c | 49 | ||||
| -rw-r--r-- | drivers/clocksource/nomadik-mtu.c | 3 | ||||
| -rw-r--r-- | drivers/clocksource/sh_cmt.c | 50 | ||||
| -rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 131 | ||||
| -rw-r--r-- | include/linux/time-armada-370-xp.h | 16 |
8 files changed, 164 insertions, 128 deletions
diff --git a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt index 36381129d141..f455182b1086 100644 --- a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt +++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | |||
| @@ -2,14 +2,40 @@ Marvell Armada 370 and Armada XP Timers | |||
| 2 | --------------------------------------- | 2 | --------------------------------------- |
| 3 | 3 | ||
| 4 | Required properties: | 4 | Required properties: |
| 5 | - compatible: Should be "marvell,armada-370-xp-timer" | 5 | - compatible: Should be either "marvell,armada-370-timer" or |
| 6 | "marvell,armada-xp-timer" as appropriate. | ||
| 6 | - interrupts: Should contain the list of Global Timer interrupts and | 7 | - interrupts: Should contain the list of Global Timer interrupts and |
| 7 | then local timer interrupts | 8 | then local timer interrupts |
| 8 | - reg: Should contain location and length for timers register. First | 9 | - reg: Should contain location and length for timers register. First |
| 9 | pair for the Global Timer registers, second pair for the | 10 | pair for the Global Timer registers, second pair for the |
| 10 | local/private timers. | 11 | local/private timers. |
| 11 | - clocks: clock driving the timer hardware | ||
| 12 | 12 | ||
| 13 | Optional properties: | 13 | Clocks required for compatible = "marvell,armada-370-timer": |
| 14 | - marvell,timer-25Mhz: Tells whether the Global timer supports the 25 | 14 | - clocks : Must contain a single entry describing the clock input |
| 15 | Mhz fixed mode (available on Armada XP and not on Armada 370) | 15 | |
| 16 | Clocks required for compatible = "marvell,armada-xp-timer": | ||
| 17 | - clocks : Must contain an entry for each entry in clock-names. | ||
| 18 | - clock-names : Must include the following entries: | ||
| 19 | "nbclk" (L2/coherency fabric clock), | ||
| 20 | "fixed" (Reference 25 MHz fixed-clock). | ||
| 21 | |||
| 22 | Examples: | ||
| 23 | |||
| 24 | - Armada 370: | ||
| 25 | |||
| 26 | timer { | ||
| 27 | compatible = "marvell,armada-370-timer"; | ||
| 28 | reg = <0x20300 0x30>, <0x21040 0x30>; | ||
| 29 | interrupts = <37>, <38>, <39>, <40>, <5>, <6>; | ||
| 30 | clocks = <&coreclk 2>; | ||
| 31 | }; | ||
| 32 | |||
| 33 | - Armada XP: | ||
| 34 | |||
| 35 | timer { | ||
| 36 | compatible = "marvell,armada-xp-timer"; | ||
| 37 | reg = <0x20300 0x30>, <0x21040 0x30>; | ||
| 38 | interrupts = <37>, <38>, <39>, <40>, <5>, <6>; | ||
| 39 | clocks = <&coreclk 2>, <&refclk>; | ||
| 40 | clock-names = "nbclk", "fixed"; | ||
| 41 | }; | ||
diff --git a/arch/arm/common/timer-sp.c b/arch/arm/common/timer-sp.c index 023ee63827a2..e901d0f3e0bb 100644 --- a/arch/arm/common/timer-sp.c +++ b/arch/arm/common/timer-sp.c | |||
| @@ -166,7 +166,8 @@ static int sp804_set_next_event(unsigned long next, | |||
| 166 | } | 166 | } |
| 167 | 167 | ||
| 168 | static struct clock_event_device sp804_clockevent = { | 168 | static struct clock_event_device sp804_clockevent = { |
| 169 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 169 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT | |
| 170 | CLOCK_EVT_FEAT_DYNIRQ, | ||
| 170 | .set_mode = sp804_set_mode, | 171 | .set_mode = sp804_set_mode, |
| 171 | .set_next_event = sp804_set_next_event, | 172 | .set_next_event = sp804_set_next_event, |
| 172 | .rating = 300, | 173 | .rating = 300, |
diff --git a/arch/arm/mach-mvebu/armada-370-xp.c b/arch/arm/mach-mvebu/armada-370-xp.c index 829b57306328..e2acff98e750 100644 --- a/arch/arm/mach-mvebu/armada-370-xp.c +++ b/arch/arm/mach-mvebu/armada-370-xp.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
| 19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
| 20 | #include <linux/io.h> | 20 | #include <linux/io.h> |
| 21 | #include <linux/time-armada-370-xp.h> | 21 | #include <linux/clocksource.h> |
| 22 | #include <linux/dma-mapping.h> | 22 | #include <linux/dma-mapping.h> |
| 23 | #include <linux/mbus.h> | 23 | #include <linux/mbus.h> |
| 24 | #include <asm/hardware/cache-l2x0.h> | 24 | #include <asm/hardware/cache-l2x0.h> |
| @@ -37,7 +37,7 @@ static void __init armada_370_xp_map_io(void) | |||
| 37 | static void __init armada_370_xp_timer_and_clk_init(void) | 37 | static void __init armada_370_xp_timer_and_clk_init(void) |
| 38 | { | 38 | { |
| 39 | of_clk_init(NULL); | 39 | of_clk_init(NULL); |
| 40 | armada_370_xp_timer_init(); | 40 | clocksource_of_init(); |
| 41 | coherency_init(); | 41 | coherency_init(); |
| 42 | BUG_ON(mvebu_mbus_dt_init()); | 42 | BUG_ON(mvebu_mbus_dt_init()); |
| 43 | #ifdef CONFIG_CACHE_L2X0 | 43 | #ifdef CONFIG_CACHE_L2X0 |
diff --git a/drivers/clocksource/em_sti.c b/drivers/clocksource/em_sti.c index 4329a29a5310..b9c81b7c3a3b 100644 --- a/drivers/clocksource/em_sti.c +++ b/drivers/clocksource/em_sti.c | |||
| @@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev) | |||
| 315 | { | 315 | { |
| 316 | struct em_sti_priv *p; | 316 | struct em_sti_priv *p; |
| 317 | struct resource *res; | 317 | struct resource *res; |
| 318 | int irq, ret; | 318 | int irq; |
| 319 | 319 | ||
| 320 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 320 | p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); |
| 321 | if (p == NULL) { | 321 | if (p == NULL) { |
| 322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | 322 | dev_err(&pdev->dev, "failed to allocate driver data\n"); |
| 323 | ret = -ENOMEM; | 323 | return -ENOMEM; |
| 324 | goto err0; | ||
| 325 | } | 324 | } |
| 326 | 325 | ||
| 327 | p->pdev = pdev; | 326 | p->pdev = pdev; |
| 328 | platform_set_drvdata(pdev, p); | 327 | platform_set_drvdata(pdev, p); |
| 329 | 328 | ||
| 330 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 331 | if (!res) { | ||
| 332 | dev_err(&pdev->dev, "failed to get I/O memory\n"); | ||
| 333 | ret = -EINVAL; | ||
| 334 | goto err0; | ||
| 335 | } | ||
| 336 | |||
| 337 | irq = platform_get_irq(pdev, 0); | 329 | irq = platform_get_irq(pdev, 0); |
| 338 | if (irq < 0) { | 330 | if (irq < 0) { |
| 339 | dev_err(&pdev->dev, "failed to get irq\n"); | 331 | dev_err(&pdev->dev, "failed to get irq\n"); |
| 340 | ret = -EINVAL; | 332 | return -EINVAL; |
| 341 | goto err0; | ||
| 342 | } | 333 | } |
| 343 | 334 | ||
| 344 | /* map memory, let base point to the STI instance */ | 335 | /* map memory, let base point to the STI instance */ |
| 345 | p->base = ioremap_nocache(res->start, resource_size(res)); | 336 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 346 | if (p->base == NULL) { | 337 | p->base = devm_ioremap_resource(&pdev->dev, res); |
| 347 | dev_err(&pdev->dev, "failed to remap I/O memory\n"); | 338 | if (IS_ERR(p->base)) |
| 348 | ret = -ENXIO; | 339 | return PTR_ERR(p->base); |
| 349 | goto err0; | ||
| 350 | } | ||
| 351 | 340 | ||
| 352 | /* get hold of clock */ | 341 | /* get hold of clock */ |
| 353 | p->clk = clk_get(&pdev->dev, "sclk"); | 342 | p->clk = devm_clk_get(&pdev->dev, "sclk"); |
| 354 | if (IS_ERR(p->clk)) { | 343 | if (IS_ERR(p->clk)) { |
| 355 | dev_err(&pdev->dev, "cannot get clock\n"); | 344 | dev_err(&pdev->dev, "cannot get clock\n"); |
| 356 | ret = PTR_ERR(p->clk); | 345 | return PTR_ERR(p->clk); |
| 357 | goto err1; | ||
| 358 | } | 346 | } |
| 359 | 347 | ||
| 360 | if (request_irq(irq, em_sti_interrupt, | 348 | if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt, |
| 361 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, | 349 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, |
| 362 | dev_name(&pdev->dev), p)) { | 350 | dev_name(&pdev->dev), p)) { |
| 363 | dev_err(&pdev->dev, "failed to request low IRQ\n"); | 351 | dev_err(&pdev->dev, "failed to request low IRQ\n"); |
| 364 | ret = -ENOENT; | 352 | return -ENOENT; |
| 365 | goto err2; | ||
| 366 | } | 353 | } |
| 367 | 354 | ||
| 368 | raw_spin_lock_init(&p->lock); | 355 | raw_spin_lock_init(&p->lock); |
| 369 | em_sti_register_clockevent(p); | 356 | em_sti_register_clockevent(p); |
| 370 | em_sti_register_clocksource(p); | 357 | em_sti_register_clocksource(p); |
| 371 | return 0; | 358 | return 0; |
| 372 | |||
| 373 | err2: | ||
| 374 | clk_put(p->clk); | ||
| 375 | err1: | ||
| 376 | iounmap(p->base); | ||
| 377 | err0: | ||
| 378 | kfree(p); | ||
| 379 | return ret; | ||
| 380 | } | 359 | } |
| 381 | 360 | ||
| 382 | static int em_sti_remove(struct platform_device *pdev) | 361 | static int em_sti_remove(struct platform_device *pdev) |
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 7d2c2c56f73c..1b74bea12385 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c | |||
| @@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev) | |||
| 165 | 165 | ||
| 166 | static struct clock_event_device nmdk_clkevt = { | 166 | static struct clock_event_device nmdk_clkevt = { |
| 167 | .name = "mtu_1", | 167 | .name = "mtu_1", |
| 168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | 168 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC | |
| 169 | CLOCK_EVT_FEAT_DYNIRQ, | ||
| 169 | .rating = 200, | 170 | .rating = 200, |
| 170 | .set_mode = nmdk_clkevt_mode, | 171 | .set_mode = nmdk_clkevt_mode, |
| 171 | .set_next_event = nmdk_clkevt_next, | 172 | .set_next_event = nmdk_clkevt_next, |
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c index 08d0c418c94a..0965e9848b3d 100644 --- a/drivers/clocksource/sh_cmt.c +++ b/drivers/clocksource/sh_cmt.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | 37 | ||
| 38 | struct sh_cmt_priv { | 38 | struct sh_cmt_priv { |
| 39 | void __iomem *mapbase; | 39 | void __iomem *mapbase; |
| 40 | void __iomem *mapbase_str; | ||
| 40 | struct clk *clk; | 41 | struct clk *clk; |
| 41 | unsigned long width; /* 16 or 32 bit version of hardware block */ | 42 | unsigned long width; /* 16 or 32 bit version of hardware block */ |
| 42 | unsigned long overflow_bit; | 43 | unsigned long overflow_bit; |
| @@ -79,6 +80,12 @@ struct sh_cmt_priv { | |||
| 79 | * CMCSR 0xffca0060 16-bit | 80 | * CMCSR 0xffca0060 16-bit |
| 80 | * CMCNT 0xffca0064 32-bit | 81 | * CMCNT 0xffca0064 32-bit |
| 81 | * CMCOR 0xffca0068 32-bit | 82 | * CMCOR 0xffca0068 32-bit |
| 83 | * | ||
| 84 | * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790: | ||
| 85 | * CMSTR 0xffca0500 32-bit | ||
| 86 | * CMCSR 0xffca0510 32-bit | ||
| 87 | * CMCNT 0xffca0514 32-bit | ||
| 88 | * CMCOR 0xffca0518 32-bit | ||
| 82 | */ | 89 | */ |
| 83 | 90 | ||
| 84 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) | 91 | static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs) |
| @@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs, | |||
| 109 | 116 | ||
| 110 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) | 117 | static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p) |
| 111 | { | 118 | { |
| 112 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 119 | return p->read_control(p->mapbase_str, 0); |
| 113 | |||
| 114 | return p->read_control(p->mapbase - cfg->channel_offset, 0); | ||
| 115 | } | 120 | } |
| 116 | 121 | ||
| 117 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) | 122 | static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p) |
| @@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p) | |||
| 127 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, | 132 | static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p, |
| 128 | unsigned long value) | 133 | unsigned long value) |
| 129 | { | 134 | { |
| 130 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | 135 | p->write_control(p->mapbase_str, 0, value); |
| 131 | |||
| 132 | p->write_control(p->mapbase - cfg->channel_offset, 0, value); | ||
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, | 138 | static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p, |
| @@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name, | |||
| 676 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | 679 | static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) |
| 677 | { | 680 | { |
| 678 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 681 | struct sh_timer_config *cfg = pdev->dev.platform_data; |
| 679 | struct resource *res; | 682 | struct resource *res, *res2; |
| 680 | int irq, ret; | 683 | int irq, ret; |
| 681 | ret = -ENXIO; | 684 | ret = -ENXIO; |
| 682 | 685 | ||
| @@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 694 | goto err0; | 697 | goto err0; |
| 695 | } | 698 | } |
| 696 | 699 | ||
| 700 | /* optional resource for the shared timer start/stop register */ | ||
| 701 | res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1); | ||
| 702 | |||
| 697 | irq = platform_get_irq(p->pdev, 0); | 703 | irq = platform_get_irq(p->pdev, 0); |
| 698 | if (irq < 0) { | 704 | if (irq < 0) { |
| 699 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 705 | dev_err(&p->pdev->dev, "failed to get irq\n"); |
| @@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 707 | goto err0; | 713 | goto err0; |
| 708 | } | 714 | } |
| 709 | 715 | ||
| 716 | /* map second resource for CMSTR */ | ||
| 717 | p->mapbase_str = ioremap_nocache(res2 ? res2->start : | ||
| 718 | res->start - cfg->channel_offset, | ||
| 719 | res2 ? resource_size(res2) : 2); | ||
| 720 | if (p->mapbase_str == NULL) { | ||
| 721 | dev_err(&p->pdev->dev, "failed to remap I/O second memory\n"); | ||
| 722 | goto err1; | ||
| 723 | } | ||
| 724 | |||
| 710 | /* request irq using setup_irq() (too early for request_irq()) */ | 725 | /* request irq using setup_irq() (too early for request_irq()) */ |
| 711 | p->irqaction.name = dev_name(&p->pdev->dev); | 726 | p->irqaction.name = dev_name(&p->pdev->dev); |
| 712 | p->irqaction.handler = sh_cmt_interrupt; | 727 | p->irqaction.handler = sh_cmt_interrupt; |
| @@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 719 | if (IS_ERR(p->clk)) { | 734 | if (IS_ERR(p->clk)) { |
| 720 | dev_err(&p->pdev->dev, "cannot get clock\n"); | 735 | dev_err(&p->pdev->dev, "cannot get clock\n"); |
| 721 | ret = PTR_ERR(p->clk); | 736 | ret = PTR_ERR(p->clk); |
| 722 | goto err1; | 737 | goto err2; |
| 723 | } | 738 | } |
| 724 | 739 | ||
| 725 | p->read_control = sh_cmt_read16; | 740 | if (res2 && (resource_size(res2) == 4)) { |
| 726 | p->write_control = sh_cmt_write16; | 741 | /* assume both CMSTR and CMCSR to be 32-bit */ |
| 742 | p->read_control = sh_cmt_read32; | ||
| 743 | p->write_control = sh_cmt_write32; | ||
| 744 | } else { | ||
| 745 | p->read_control = sh_cmt_read16; | ||
| 746 | p->write_control = sh_cmt_write16; | ||
| 747 | } | ||
| 727 | 748 | ||
| 728 | if (resource_size(res) == 6) { | 749 | if (resource_size(res) == 6) { |
| 729 | p->width = 16; | 750 | p->width = 16; |
| @@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev) | |||
| 752 | cfg->clocksource_rating); | 773 | cfg->clocksource_rating); |
| 753 | if (ret) { | 774 | if (ret) { |
| 754 | dev_err(&p->pdev->dev, "registration failed\n"); | 775 | dev_err(&p->pdev->dev, "registration failed\n"); |
| 755 | goto err2; | 776 | goto err3; |
| 756 | } | 777 | } |
| 757 | p->cs_enabled = false; | 778 | p->cs_enabled = false; |
| 758 | 779 | ||
| 759 | ret = setup_irq(irq, &p->irqaction); | 780 | ret = setup_irq(irq, &p->irqaction); |
| 760 | if (ret) { | 781 | if (ret) { |
| 761 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); | 782 | dev_err(&p->pdev->dev, "failed to request irq %d\n", irq); |
| 762 | goto err2; | 783 | goto err3; |
| 763 | } | 784 | } |
| 764 | 785 | ||
| 765 | platform_set_drvdata(pdev, p); | 786 | platform_set_drvdata(pdev, p); |
| 766 | 787 | ||
| 767 | return 0; | 788 | return 0; |
| 768 | err2: | 789 | err3: |
| 769 | clk_put(p->clk); | 790 | clk_put(p->clk); |
| 770 | 791 | err2: | |
| 792 | iounmap(p->mapbase_str); | ||
| 771 | err1: | 793 | err1: |
| 772 | iounmap(p->mapbase); | 794 | iounmap(p->mapbase); |
| 773 | err0: | 795 | err0: |
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index 847cab6f6e31..0198504ef6b0 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
| @@ -13,6 +13,19 @@ | |||
| 13 | * | 13 | * |
| 14 | * Timer 0 is used as free-running clocksource, while timer 1 is | 14 | * Timer 0 is used as free-running clocksource, while timer 1 is |
| 15 | * used as clock_event_device. | 15 | * used as clock_event_device. |
| 16 | * | ||
| 17 | * --- | ||
| 18 | * Clocksource driver for Armada 370 and Armada XP SoC. | ||
| 19 | * This driver implements one compatible string for each SoC, given | ||
| 20 | * each has its own characteristics: | ||
| 21 | * | ||
| 22 | * * Armada 370 has no 25 MHz fixed timer. | ||
| 23 | * | ||
| 24 | * * Armada XP cannot work properly without such 25 MHz fixed timer as | ||
| 25 | * doing otherwise leads to using a clocksource whose frequency varies | ||
| 26 | * when doing cpufreq frequency changes. | ||
| 27 | * | ||
| 28 | * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt | ||
| 16 | */ | 29 | */ |
| 17 | 30 | ||
| 18 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| @@ -30,19 +43,18 @@ | |||
| 30 | #include <linux/module.h> | 43 | #include <linux/module.h> |
| 31 | #include <linux/sched_clock.h> | 44 | #include <linux/sched_clock.h> |
| 32 | #include <linux/percpu.h> | 45 | #include <linux/percpu.h> |
| 33 | #include <linux/time-armada-370-xp.h> | ||
| 34 | 46 | ||
| 35 | /* | 47 | /* |
| 36 | * Timer block registers. | 48 | * Timer block registers. |
| 37 | */ | 49 | */ |
| 38 | #define TIMER_CTRL_OFF 0x0000 | 50 | #define TIMER_CTRL_OFF 0x0000 |
| 39 | #define TIMER0_EN 0x0001 | 51 | #define TIMER0_EN BIT(0) |
| 40 | #define TIMER0_RELOAD_EN 0x0002 | 52 | #define TIMER0_RELOAD_EN BIT(1) |
| 41 | #define TIMER0_25MHZ 0x0800 | 53 | #define TIMER0_25MHZ BIT(11) |
| 42 | #define TIMER0_DIV(div) ((div) << 19) | 54 | #define TIMER0_DIV(div) ((div) << 19) |
| 43 | #define TIMER1_EN 0x0004 | 55 | #define TIMER1_EN BIT(2) |
| 44 | #define TIMER1_RELOAD_EN 0x0008 | 56 | #define TIMER1_RELOAD_EN BIT(3) |
| 45 | #define TIMER1_25MHZ 0x1000 | 57 | #define TIMER1_25MHZ BIT(12) |
| 46 | #define TIMER1_DIV(div) ((div) << 22) | 58 | #define TIMER1_DIV(div) ((div) << 22) |
| 47 | #define TIMER_EVENTS_STATUS 0x0004 | 59 | #define TIMER_EVENTS_STATUS 0x0004 |
| 48 | #define TIMER0_CLR_MASK (~0x1) | 60 | #define TIMER0_CLR_MASK (~0x1) |
| @@ -72,6 +84,18 @@ static u32 ticks_per_jiffy; | |||
| 72 | 84 | ||
| 73 | static struct clock_event_device __percpu *armada_370_xp_evt; | 85 | static struct clock_event_device __percpu *armada_370_xp_evt; |
| 74 | 86 | ||
| 87 | static void timer_ctrl_clrset(u32 clr, u32 set) | ||
| 88 | { | ||
| 89 | writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
| 90 | timer_base + TIMER_CTRL_OFF); | ||
| 91 | } | ||
| 92 | |||
| 93 | static void local_timer_ctrl_clrset(u32 clr, u32 set) | ||
| 94 | { | ||
| 95 | writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set, | ||
| 96 | local_base + TIMER_CTRL_OFF); | ||
| 97 | } | ||
| 98 | |||
| 75 | static u32 notrace armada_370_xp_read_sched_clock(void) | 99 | static u32 notrace armada_370_xp_read_sched_clock(void) |
| 76 | { | 100 | { |
| 77 | return ~readl(timer_base + TIMER0_VAL_OFF); | 101 | return ~readl(timer_base + TIMER0_VAL_OFF); |
| @@ -84,7 +108,6 @@ static int | |||
| 84 | armada_370_xp_clkevt_next_event(unsigned long delta, | 108 | armada_370_xp_clkevt_next_event(unsigned long delta, |
| 85 | struct clock_event_device *dev) | 109 | struct clock_event_device *dev) |
| 86 | { | 110 | { |
| 87 | u32 u; | ||
| 88 | /* | 111 | /* |
| 89 | * Clear clockevent timer interrupt. | 112 | * Clear clockevent timer interrupt. |
| 90 | */ | 113 | */ |
| @@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta, | |||
| 98 | /* | 121 | /* |
| 99 | * Enable the timer. | 122 | * Enable the timer. |
| 100 | */ | 123 | */ |
| 101 | u = readl(local_base + TIMER_CTRL_OFF); | 124 | local_timer_ctrl_clrset(TIMER0_RELOAD_EN, |
| 102 | u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | | 125 | TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); |
| 103 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | ||
| 104 | writel(u, local_base + TIMER_CTRL_OFF); | ||
| 105 | |||
| 106 | return 0; | 126 | return 0; |
| 107 | } | 127 | } |
| 108 | 128 | ||
| @@ -110,8 +130,6 @@ static void | |||
| 110 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, | 130 | armada_370_xp_clkevt_mode(enum clock_event_mode mode, |
| 111 | struct clock_event_device *dev) | 131 | struct clock_event_device *dev) |
| 112 | { | 132 | { |
| 113 | u32 u; | ||
| 114 | |||
| 115 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 133 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
| 116 | 134 | ||
| 117 | /* | 135 | /* |
| @@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
| 123 | /* | 141 | /* |
| 124 | * Enable timer. | 142 | * Enable timer. |
| 125 | */ | 143 | */ |
| 126 | 144 | local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN | | |
| 127 | u = readl(local_base + TIMER_CTRL_OFF); | 145 | TIMER0_EN | |
| 128 | 146 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
| 129 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
| 130 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), | ||
| 131 | local_base + TIMER_CTRL_OFF); | ||
| 132 | } else { | 147 | } else { |
| 133 | /* | 148 | /* |
| 134 | * Disable timer. | 149 | * Disable timer. |
| 135 | */ | 150 | */ |
| 136 | u = readl(local_base + TIMER_CTRL_OFF); | 151 | local_timer_ctrl_clrset(TIMER0_EN, 0); |
| 137 | writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); | ||
| 138 | 152 | ||
| 139 | /* | 153 | /* |
| 140 | * ACK pending timer interrupt. | 154 | * ACK pending timer interrupt. |
| @@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | |||
| 163 | */ | 177 | */ |
| 164 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) | 178 | static int armada_370_xp_timer_setup(struct clock_event_device *evt) |
| 165 | { | 179 | { |
| 166 | u32 u; | 180 | u32 clr = 0, set = 0; |
| 167 | int cpu = smp_processor_id(); | 181 | int cpu = smp_processor_id(); |
| 168 | 182 | ||
| 169 | u = readl(local_base + TIMER_CTRL_OFF); | ||
| 170 | if (timer25Mhz) | 183 | if (timer25Mhz) |
| 171 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 184 | set = TIMER0_25MHZ; |
| 172 | else | 185 | else |
| 173 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 186 | clr = TIMER0_25MHZ; |
| 187 | local_timer_ctrl_clrset(clr, set); | ||
| 174 | 188 | ||
| 175 | evt->name = "armada_370_xp_per_cpu_tick", | 189 | evt->name = "armada_370_xp_per_cpu_tick", |
| 176 | evt->features = CLOCK_EVT_FEAT_ONESHOT | | 190 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
| @@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = { | |||
| 217 | .notifier_call = armada_370_xp_timer_cpu_notify, | 231 | .notifier_call = armada_370_xp_timer_cpu_notify, |
| 218 | }; | 232 | }; |
| 219 | 233 | ||
| 220 | void __init armada_370_xp_timer_init(void) | 234 | static void __init armada_370_xp_timer_common_init(struct device_node *np) |
| 221 | { | 235 | { |
| 222 | u32 u; | 236 | u32 clr = 0, set = 0; |
| 223 | struct device_node *np; | ||
| 224 | int res; | 237 | int res; |
| 225 | 238 | ||
| 226 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); | ||
| 227 | timer_base = of_iomap(np, 0); | 239 | timer_base = of_iomap(np, 0); |
| 228 | WARN_ON(!timer_base); | 240 | WARN_ON(!timer_base); |
| 229 | local_base = of_iomap(np, 1); | 241 | local_base = of_iomap(np, 1); |
| 230 | 242 | ||
| 231 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 243 | if (timer25Mhz) |
| 232 | /* The fixed 25MHz timer is available so let's use it */ | 244 | set = TIMER0_25MHZ; |
| 233 | u = readl(timer_base + TIMER_CTRL_OFF); | 245 | else |
| 234 | writel(u | TIMER0_25MHZ, | 246 | clr = TIMER0_25MHZ; |
| 235 | timer_base + TIMER_CTRL_OFF); | 247 | timer_ctrl_clrset(clr, set); |
| 236 | timer_clk = 25000000; | 248 | local_timer_ctrl_clrset(clr, set); |
| 237 | } else { | ||
| 238 | unsigned long rate = 0; | ||
| 239 | struct clk *clk = of_clk_get(np, 0); | ||
| 240 | WARN_ON(IS_ERR(clk)); | ||
| 241 | rate = clk_get_rate(clk); | ||
| 242 | |||
| 243 | u = readl(timer_base + TIMER_CTRL_OFF); | ||
| 244 | writel(u & ~(TIMER0_25MHZ), | ||
| 245 | timer_base + TIMER_CTRL_OFF); | ||
| 246 | |||
| 247 | timer_clk = rate / TIMER_DIVIDER; | ||
| 248 | timer25Mhz = false; | ||
| 249 | } | ||
| 250 | 249 | ||
| 251 | /* | 250 | /* |
| 252 | * We use timer 0 as clocksource, and private(local) timer 0 | 251 | * We use timer 0 as clocksource, and private(local) timer 0 |
| @@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void) | |||
| 268 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); | 267 | writel(0xffffffff, timer_base + TIMER0_VAL_OFF); |
| 269 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); | 268 | writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF); |
| 270 | 269 | ||
| 271 | u = readl(timer_base + TIMER_CTRL_OFF); | 270 | timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN | |
| 272 | 271 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); | |
| 273 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | | ||
| 274 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF); | ||
| 275 | 272 | ||
| 276 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, | 273 | clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, |
| 277 | "armada_370_xp_clocksource", | 274 | "armada_370_xp_clocksource", |
| @@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void) | |||
| 293 | if (!res) | 290 | if (!res) |
| 294 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); | 291 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); |
| 295 | } | 292 | } |
| 293 | |||
| 294 | static void __init armada_xp_timer_init(struct device_node *np) | ||
| 295 | { | ||
| 296 | struct clk *clk = of_clk_get_by_name(np, "fixed"); | ||
| 297 | |||
| 298 | /* The 25Mhz fixed clock is mandatory, and must always be available */ | ||
| 299 | BUG_ON(IS_ERR(clk)); | ||
| 300 | timer_clk = clk_get_rate(clk); | ||
| 301 | |||
| 302 | armada_370_xp_timer_common_init(np); | ||
| 303 | } | ||
| 304 | CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer", | ||
| 305 | armada_xp_timer_init); | ||
| 306 | |||
| 307 | static void __init armada_370_timer_init(struct device_node *np) | ||
| 308 | { | ||
| 309 | struct clk *clk = of_clk_get(np, 0); | ||
| 310 | |||
| 311 | BUG_ON(IS_ERR(clk)); | ||
| 312 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; | ||
| 313 | timer25Mhz = false; | ||
| 314 | |||
| 315 | armada_370_xp_timer_common_init(np); | ||
| 316 | } | ||
| 317 | CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer", | ||
| 318 | armada_370_timer_init); | ||
diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h deleted file mode 100644 index 6fb0856b9405..000000000000 --- a/include/linux/time-armada-370-xp.h +++ /dev/null | |||
| @@ -1,16 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Marvell Armada 370/XP SoC timer handling. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Marvell | ||
| 5 | * | ||
| 6 | * Lior Amsalem <alior@marvell.com> | ||
| 7 | * Gregory CLEMENT <gregory.clement@free-electrons.com> | ||
| 8 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | ||
| 9 | * | ||
| 10 | */ | ||
| 11 | #ifndef __TIME_ARMADA_370_XPPRCMU_H | ||
| 12 | #define __TIME_ARMADA_370_XPPRCMU_H | ||
| 13 | |||
| 14 | void armada_370_xp_timer_init(void); | ||
| 15 | |||
| 16 | #endif | ||
