.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* linux/arch/arm/mach-exynos4/mct.c |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. |
---|
4 | 5 | * http://www.samsung.com |
---|
5 | 6 | * |
---|
6 | | - * EXYNOS4 MCT(Multi-Core Timer) support |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License version 2 as |
---|
10 | | - * published by the Free Software Foundation. |
---|
| 7 | + * Exynos4 MCT(Multi-Core Timer) support |
---|
11 | 8 | */ |
---|
12 | 9 | |
---|
13 | | -#include <linux/sched.h> |
---|
14 | 10 | #include <linux/interrupt.h> |
---|
15 | 11 | #include <linux/irq.h> |
---|
16 | 12 | #include <linux/err.h> |
---|
17 | 13 | #include <linux/clk.h> |
---|
18 | 14 | #include <linux/clockchips.h> |
---|
19 | 15 | #include <linux/cpu.h> |
---|
20 | | -#include <linux/platform_device.h> |
---|
21 | 16 | #include <linux/delay.h> |
---|
22 | 17 | #include <linux/percpu.h> |
---|
23 | 18 | #include <linux/of.h> |
---|
.. | .. |
---|
334 | 329 | return IRQ_HANDLED; |
---|
335 | 330 | } |
---|
336 | 331 | |
---|
337 | | -static struct irqaction mct_comp_event_irq = { |
---|
338 | | - .name = "mct_comp_irq", |
---|
339 | | - .flags = IRQF_TIMER | IRQF_IRQPOLL, |
---|
340 | | - .handler = exynos4_mct_comp_isr, |
---|
341 | | - .dev_id = &mct_comp_device, |
---|
342 | | -}; |
---|
343 | | - |
---|
344 | 332 | static int exynos4_clockevent_init(void) |
---|
345 | 333 | { |
---|
346 | 334 | mct_comp_device.cpumask = cpumask_of(0); |
---|
347 | 335 | clockevents_config_and_register(&mct_comp_device, clk_rate, |
---|
348 | 336 | 0xf, 0xffffffff); |
---|
349 | | - setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); |
---|
| 337 | + if (request_irq(mct_irqs[MCT_G0_IRQ], exynos4_mct_comp_isr, |
---|
| 338 | + IRQF_TIMER | IRQF_IRQPOLL, "mct_comp_irq", |
---|
| 339 | + &mct_comp_device)) |
---|
| 340 | + pr_err("%s: request_irq() failed\n", "mct_comp_irq"); |
---|
350 | 341 | |
---|
351 | 342 | return 0; |
---|
352 | 343 | } |
---|
.. | .. |
---|
503 | 494 | return 0; |
---|
504 | 495 | } |
---|
505 | 496 | |
---|
506 | | -static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base) |
---|
| 497 | +static int __init exynos4_timer_resources(struct device_node *np) |
---|
507 | 498 | { |
---|
508 | | - int err, cpu; |
---|
509 | 499 | struct clk *mct_clk, *tick_clk; |
---|
510 | 500 | |
---|
511 | | - tick_clk = np ? of_clk_get_by_name(np, "fin_pll") : |
---|
512 | | - clk_get(NULL, "fin_pll"); |
---|
| 501 | + reg_base = of_iomap(np, 0); |
---|
| 502 | + if (!reg_base) |
---|
| 503 | + panic("%s: unable to ioremap mct address space\n", __func__); |
---|
| 504 | + |
---|
| 505 | + tick_clk = of_clk_get_by_name(np, "fin_pll"); |
---|
513 | 506 | if (IS_ERR(tick_clk)) |
---|
514 | 507 | panic("%s: unable to determine tick clock rate\n", __func__); |
---|
515 | 508 | clk_rate = clk_get_rate(tick_clk); |
---|
516 | 509 | |
---|
517 | | - mct_clk = np ? of_clk_get_by_name(np, "mct") : clk_get(NULL, "mct"); |
---|
| 510 | + mct_clk = of_clk_get_by_name(np, "mct"); |
---|
518 | 511 | if (IS_ERR(mct_clk)) |
---|
519 | 512 | panic("%s: unable to retrieve mct clock instance\n", __func__); |
---|
520 | 513 | clk_prepare_enable(mct_clk); |
---|
521 | 514 | |
---|
522 | | - reg_base = base; |
---|
523 | | - if (!reg_base) |
---|
524 | | - panic("%s: unable to ioremap mct address space\n", __func__); |
---|
| 515 | + return 0; |
---|
| 516 | +} |
---|
| 517 | + |
---|
| 518 | +static int __init exynos4_timer_interrupts(struct device_node *np, |
---|
| 519 | + unsigned int int_type) |
---|
| 520 | +{ |
---|
| 521 | + int nr_irqs, i, err, cpu; |
---|
| 522 | + |
---|
| 523 | + mct_int_type = int_type; |
---|
| 524 | + |
---|
| 525 | + /* This driver uses only one global timer interrupt */ |
---|
| 526 | + mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); |
---|
| 527 | + |
---|
| 528 | + /* |
---|
| 529 | + * Find out the number of local irqs specified. The local |
---|
| 530 | + * timer irqs are specified after the four global timer |
---|
| 531 | + * irqs are specified. |
---|
| 532 | + */ |
---|
| 533 | + nr_irqs = of_irq_count(np); |
---|
| 534 | + if (nr_irqs > ARRAY_SIZE(mct_irqs)) { |
---|
| 535 | + pr_err("exynos-mct: too many (%d) interrupts configured in DT\n", |
---|
| 536 | + nr_irqs); |
---|
| 537 | + nr_irqs = ARRAY_SIZE(mct_irqs); |
---|
| 538 | + } |
---|
| 539 | + for (i = MCT_L0_IRQ; i < nr_irqs; i++) |
---|
| 540 | + mct_irqs[i] = irq_of_parse_and_map(np, i); |
---|
525 | 541 | |
---|
526 | 542 | if (mct_int_type == MCT_INT_PPI) { |
---|
527 | 543 | |
---|
.. | .. |
---|
532 | 548 | mct_irqs[MCT_L0_IRQ], err); |
---|
533 | 549 | } else { |
---|
534 | 550 | for_each_possible_cpu(cpu) { |
---|
535 | | - int mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; |
---|
| 551 | + int mct_irq; |
---|
536 | 552 | struct mct_clock_event_device *pcpu_mevt = |
---|
537 | 553 | per_cpu_ptr(&percpu_mct_tick, cpu); |
---|
538 | 554 | |
---|
539 | 555 | pcpu_mevt->evt.irq = -1; |
---|
| 556 | + if (MCT_L0_IRQ + cpu >= ARRAY_SIZE(mct_irqs)) |
---|
| 557 | + break; |
---|
| 558 | + mct_irq = mct_irqs[MCT_L0_IRQ + cpu]; |
---|
540 | 559 | |
---|
541 | 560 | irq_set_status_flags(mct_irq, IRQ_NOAUTOEN); |
---|
542 | 561 | if (request_irq(mct_irq, |
---|
.. | .. |
---|
581 | 600 | |
---|
582 | 601 | static int __init mct_init_dt(struct device_node *np, unsigned int int_type) |
---|
583 | 602 | { |
---|
584 | | - u32 nr_irqs, i; |
---|
585 | 603 | int ret; |
---|
586 | 604 | |
---|
587 | | - mct_int_type = int_type; |
---|
| 605 | + ret = exynos4_timer_resources(np); |
---|
| 606 | + if (ret) |
---|
| 607 | + return ret; |
---|
588 | 608 | |
---|
589 | | - /* This driver uses only one global timer interrupt */ |
---|
590 | | - mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); |
---|
591 | | - |
---|
592 | | - /* |
---|
593 | | - * Find out the number of local irqs specified. The local |
---|
594 | | - * timer irqs are specified after the four global timer |
---|
595 | | - * irqs are specified. |
---|
596 | | - */ |
---|
597 | | -#ifdef CONFIG_OF |
---|
598 | | - nr_irqs = of_irq_count(np); |
---|
599 | | -#else |
---|
600 | | - nr_irqs = 0; |
---|
601 | | -#endif |
---|
602 | | - for (i = MCT_L0_IRQ; i < nr_irqs; i++) |
---|
603 | | - mct_irqs[i] = irq_of_parse_and_map(np, i); |
---|
604 | | - |
---|
605 | | - ret = exynos4_timer_resources(np, of_iomap(np, 0)); |
---|
| 609 | + ret = exynos4_timer_interrupts(np, int_type); |
---|
606 | 610 | if (ret) |
---|
607 | 611 | return ret; |
---|
608 | 612 | |
---|