cevt-gic.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 2013 Imagination Technologies Ltd.
  7. */
  8. #include <linux/clockchips.h>
  9. #include <linux/interrupt.h>
  10. #include <linux/percpu.h>
  11. #include <linux/smp.h>
  12. #include <linux/irq.h>
  13. #include <asm/time.h>
  14. #include <asm/gic.h>
  15. #include <asm/mips-boards/maltaint.h>
  16. DEFINE_PER_CPU(struct clock_event_device, gic_clockevent_device);
  17. int gic_timer_irq_installed;
  18. static int gic_next_event(unsigned long delta, struct clock_event_device *evt)
  19. {
  20. u64 cnt;
  21. int res;
  22. cnt = gic_read_count();
  23. cnt += (u64)delta;
  24. gic_write_compare(cnt);
  25. res = ((int)(gic_read_count() - cnt) >= 0) ? -ETIME : 0;
  26. return res;
  27. }
  28. void gic_set_clock_mode(enum clock_event_mode mode,
  29. struct clock_event_device *evt)
  30. {
  31. /* Nothing to do ... */
  32. }
  33. irqreturn_t gic_compare_interrupt(int irq, void *dev_id)
  34. {
  35. struct clock_event_device *cd;
  36. int cpu = smp_processor_id();
  37. gic_write_compare(gic_read_compare());
  38. cd = &per_cpu(gic_clockevent_device, cpu);
  39. cd->event_handler(cd);
  40. return IRQ_HANDLED;
  41. }
  42. struct irqaction gic_compare_irqaction = {
  43. .handler = gic_compare_interrupt,
  44. .flags = IRQF_PERCPU | IRQF_TIMER,
  45. .name = "timer",
  46. };
  47. void gic_event_handler(struct clock_event_device *dev)
  48. {
  49. }
  50. int __cpuinit gic_clockevent_init(void)
  51. {
  52. unsigned int cpu = smp_processor_id();
  53. struct clock_event_device *cd;
  54. unsigned int irq;
  55. if (!cpu_has_counter || !gic_frequency)
  56. return -ENXIO;
  57. irq = MIPS_GIC_IRQ_BASE;
  58. cd = &per_cpu(gic_clockevent_device, cpu);
  59. cd->name = "MIPS GIC";
  60. cd->features = CLOCK_EVT_FEAT_ONESHOT;
  61. clockevent_set_clock(cd, gic_frequency);
  62. /* Calculate the min / max delta */
  63. cd->max_delta_ns = clockevent_delta2ns(0x7fffffff, cd);
  64. cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
  65. cd->rating = 300;
  66. cd->irq = irq;
  67. cd->cpumask = cpumask_of(cpu);
  68. cd->set_next_event = gic_next_event;
  69. cd->set_mode = gic_set_clock_mode;
  70. cd->event_handler = gic_event_handler;
  71. clockevents_register_device(cd);
  72. GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 0x80000002);
  73. GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK);
  74. if (gic_timer_irq_installed)
  75. return 0;
  76. gic_timer_irq_installed = 1;
  77. setup_irq(irq, &gic_compare_irqaction);
  78. irq_set_handler(irq, handle_percpu_irq);
  79. return 0;
  80. }