diff options
| -rw-r--r-- | arch/arm/mach-omap2/timer-gp.c | 147 | ||||
| -rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 1 |
2 files changed, 113 insertions, 35 deletions
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index a0d8e83594eb..62c0d5cb25f7 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c | |||
| @@ -45,10 +45,33 @@ | |||
| 45 | 45 | ||
| 46 | #include "timer-gp.h" | 46 | #include "timer-gp.h" |
| 47 | 47 | ||
| 48 | /* Parent clocks, eventually these will come from the clock framework */ | ||
| 49 | |||
| 50 | #define OMAP2_MPU_SOURCE "sys_ck" | ||
| 51 | #define OMAP3_MPU_SOURCE OMAP2_MPU_SOURCE | ||
| 52 | #define OMAP4_MPU_SOURCE "sys_clkin_ck" | ||
| 53 | #define OMAP2_32K_SOURCE "func_32k_ck" | ||
| 54 | #define OMAP3_32K_SOURCE "omap_32k_fck" | ||
| 55 | #define OMAP4_32K_SOURCE "sys_32k_ck" | ||
| 56 | |||
| 57 | #ifdef CONFIG_OMAP_32K_TIMER | ||
| 58 | #define OMAP2_CLKEV_SOURCE OMAP2_32K_SOURCE | ||
| 59 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE | ||
| 60 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE | ||
| 61 | #define OMAP3_SECURE_TIMER 12 | ||
| 62 | #else | ||
| 63 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE | ||
| 64 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE | ||
| 65 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE | ||
| 66 | #define OMAP3_SECURE_TIMER 1 | ||
| 67 | #endif | ||
| 48 | 68 | ||
| 49 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ | 69 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ |
| 50 | #define MAX_GPTIMER_ID 12 | 70 | #define MAX_GPTIMER_ID 12 |
| 51 | 71 | ||
| 72 | /* Clockevent code */ | ||
| 73 | |||
| 74 | static struct omap_dm_timer clkev; | ||
| 52 | static struct omap_dm_timer *gptimer; | 75 | static struct omap_dm_timer *gptimer; |
| 53 | static struct clock_event_device clockevent_gpt; | 76 | static struct clock_event_device clockevent_gpt; |
| 54 | static u8 __initdata gptimer_id = 1; | 77 | static u8 __initdata gptimer_id = 1; |
| @@ -57,10 +80,9 @@ struct omap_dm_timer *gptimer_wakeup; | |||
| 57 | 80 | ||
| 58 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) | 81 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) |
| 59 | { | 82 | { |
| 60 | struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id; | ||
| 61 | struct clock_event_device *evt = &clockevent_gpt; | 83 | struct clock_event_device *evt = &clockevent_gpt; |
| 62 | 84 | ||
| 63 | omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW); | 85 | __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); |
| 64 | 86 | ||
| 65 | evt->event_handler(evt); | 87 | evt->event_handler(evt); |
| 66 | return IRQ_HANDLED; | 88 | return IRQ_HANDLED; |
| @@ -75,7 +97,8 @@ static struct irqaction omap2_gp_timer_irq = { | |||
| 75 | static int omap2_gp_timer_set_next_event(unsigned long cycles, | 97 | static int omap2_gp_timer_set_next_event(unsigned long cycles, |
| 76 | struct clock_event_device *evt) | 98 | struct clock_event_device *evt) |
| 77 | { | 99 | { |
| 78 | omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles); | 100 | __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST, |
| 101 | 0xffffffff - cycles, 1); | ||
| 79 | 102 | ||
| 80 | return 0; | 103 | return 0; |
| 81 | } | 104 | } |
| @@ -85,13 +108,18 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
| 85 | { | 108 | { |
| 86 | u32 period; | 109 | u32 period; |
| 87 | 110 | ||
| 88 | omap_dm_timer_stop(gptimer); | 111 | __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate); |
| 89 | 112 | ||
| 90 | switch (mode) { | 113 | switch (mode) { |
| 91 | case CLOCK_EVT_MODE_PERIODIC: | 114 | case CLOCK_EVT_MODE_PERIODIC: |
| 92 | period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; | 115 | period = clkev.rate / HZ; |
| 93 | period -= 1; | 116 | period -= 1; |
| 94 | omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period); | 117 | /* Looks like we need to first set the load value separately */ |
| 118 | __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG, | ||
| 119 | 0xffffffff - period, 1); | ||
| 120 | __omap_dm_timer_load_start(clkev.io_base, | ||
| 121 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, | ||
| 122 | 0xffffffff - period, 1); | ||
| 95 | break; | 123 | break; |
| 96 | case CLOCK_EVT_MODE_ONESHOT: | 124 | case CLOCK_EVT_MODE_ONESHOT: |
| 97 | break; | 125 | break; |
| @@ -130,43 +158,89 @@ int __init omap2_gp_clockevent_set_gptimer(u8 id) | |||
| 130 | return 0; | 158 | return 0; |
| 131 | } | 159 | } |
| 132 | 160 | ||
| 133 | static void __init omap2_gp_clockevent_init(void) | 161 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
| 162 | int gptimer_id, | ||
| 163 | const char *fck_source) | ||
| 134 | { | 164 | { |
| 135 | u32 tick_rate; | 165 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ |
| 136 | int src; | 166 | struct omap_hwmod *oh; |
| 137 | char clockevent_hwmod_name[8]; /* 8 = sizeof("timerXX0") */ | 167 | size_t size; |
| 168 | int res = 0; | ||
| 169 | |||
| 170 | sprintf(name, "timer%d", gptimer_id); | ||
| 171 | omap_hwmod_setup_one(name); | ||
| 172 | oh = omap_hwmod_lookup(name); | ||
| 173 | if (!oh) | ||
| 174 | return -ENODEV; | ||
| 175 | |||
| 176 | timer->irq = oh->mpu_irqs[0].irq; | ||
| 177 | timer->phys_base = oh->slaves[0]->addr->pa_start; | ||
| 178 | size = oh->slaves[0]->addr->pa_end - timer->phys_base; | ||
| 179 | |||
| 180 | /* Static mapping, never released */ | ||
| 181 | timer->io_base = ioremap(timer->phys_base, size); | ||
| 182 | if (!timer->io_base) | ||
| 183 | return -ENXIO; | ||
| 184 | |||
| 185 | /* After the dmtimer is using hwmod these clocks won't be needed */ | ||
| 186 | sprintf(name, "gpt%d_fck", gptimer_id); | ||
| 187 | timer->fclk = clk_get(NULL, name); | ||
| 188 | if (IS_ERR(timer->fclk)) | ||
| 189 | return -ENODEV; | ||
| 190 | |||
| 191 | sprintf(name, "gpt%d_ick", gptimer_id); | ||
| 192 | timer->iclk = clk_get(NULL, name); | ||
| 193 | if (IS_ERR(timer->iclk)) { | ||
| 194 | clk_put(timer->fclk); | ||
| 195 | return -ENODEV; | ||
| 196 | } | ||
| 138 | 197 | ||
| 139 | inited = 1; | 198 | omap_hwmod_enable(oh); |
| 199 | |||
| 200 | if (gptimer_id != 12) { | ||
| 201 | struct clk *src; | ||
| 202 | |||
| 203 | src = clk_get(NULL, fck_source); | ||
| 204 | if (IS_ERR(src)) { | ||
| 205 | res = -EINVAL; | ||
| 206 | } else { | ||
| 207 | res = __omap_dm_timer_set_source(timer->fclk, src); | ||
| 208 | if (IS_ERR_VALUE(res)) | ||
| 209 | pr_warning("%s: timer%i cannot set source\n", | ||
| 210 | __func__, gptimer_id); | ||
| 211 | clk_put(src); | ||
| 212 | } | ||
| 213 | } | ||
| 214 | __omap_dm_timer_reset(timer->io_base, 1, 1); | ||
| 215 | timer->posted = 1; | ||
| 216 | |||
| 217 | timer->rate = clk_get_rate(timer->fclk); | ||
| 140 | 218 | ||
| 141 | sprintf(clockevent_hwmod_name, "timer%d", gptimer_id); | 219 | timer->reserved = 1; |
| 142 | omap_hwmod_setup_one(clockevent_hwmod_name); | ||
| 143 | 220 | ||
| 144 | gptimer = omap_dm_timer_request_specific(gptimer_id); | 221 | gptimer = omap_dm_timer_request_specific(gptimer_id); |
| 145 | BUG_ON(gptimer == NULL); | 222 | BUG_ON(gptimer == NULL); |
| 146 | gptimer_wakeup = gptimer; | 223 | gptimer_wakeup = gptimer; |
| 147 | 224 | ||
| 148 | #if defined(CONFIG_OMAP_32K_TIMER) | 225 | return res; |
| 149 | src = OMAP_TIMER_SRC_32_KHZ; | 226 | } |
| 150 | #else | ||
| 151 | src = OMAP_TIMER_SRC_SYS_CLK; | ||
| 152 | WARN(gptimer_id == 12, "WARNING: GPTIMER12 can only use the " | ||
| 153 | "secure 32KiHz clock source\n"); | ||
| 154 | #endif | ||
| 155 | 227 | ||
| 156 | if (gptimer_id != 12) | 228 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
| 157 | WARN(IS_ERR_VALUE(omap_dm_timer_set_source(gptimer, src)), | 229 | const char *fck_source) |
| 158 | "timer-gp: omap_dm_timer_set_source() failed\n"); | 230 | { |
| 231 | int res; | ||
| 159 | 232 | ||
| 160 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer)); | 233 | inited = 1; |
| 161 | 234 | ||
| 162 | pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n", | 235 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source); |
| 163 | gptimer_id, tick_rate); | ||
