1/* 2 * linux/arch/arm/plat-omap/dmtimer.c 3 * 4 * OMAP Dual-Mode Timers 5 * 6 * Copyright (C) 2005 Nokia Corporation 7 * OMAP2 support by Juha Yrjola 8 * API improvements and OMAP2 clock framework support by Timo Teras 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 16 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 18 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * You should have received a copy of the GNU General Public License along 25 * with this program; if not, write to the Free Software Foundation, Inc., 26 * 675 Mass Ave, Cambridge, MA 02139, USA. 27 */ 28 29#include <linux/init.h> 30#include <linux/spinlock.h> 31#include <linux/errno.h> 32#include <linux/list.h> 33#include <linux/clk.h> 34#include <linux/delay.h> 35#include <asm/hardware.h> 36#include <asm/arch/dmtimer.h> 37#include <asm/io.h> 38#include <asm/arch/irqs.h> 39 40/* register offsets */ 41#define OMAP_TIMER_ID_REG 0x00 42#define OMAP_TIMER_OCP_CFG_REG 0x10 43#define OMAP_TIMER_SYS_STAT_REG 0x14 44#define OMAP_TIMER_STAT_REG 0x18 45#define OMAP_TIMER_INT_EN_REG 0x1c 46#define OMAP_TIMER_WAKEUP_EN_REG 0x20 47#define OMAP_TIMER_CTRL_REG 0x24 48#define OMAP_TIMER_COUNTER_REG 0x28 49#define OMAP_TIMER_LOAD_REG 0x2c 50#define OMAP_TIMER_TRIGGER_REG 0x30 51#define OMAP_TIMER_WRITE_PEND_REG 0x34 52#define OMAP_TIMER_MATCH_REG 0x38 53#define OMAP_TIMER_CAPTURE_REG 0x3c 54#define OMAP_TIMER_IF_CTRL_REG 0x40 55 56/* timer control reg bits */ 57#define OMAP_TIMER_CTRL_GPOCFG (1 << 14) 58#define OMAP_TIMER_CTRL_CAPTMODE (1 << 13) 59#define OMAP_TIMER_CTRL_PT (1 << 12) 60#define OMAP_TIMER_CTRL_TCM_LOWTOHIGH (0x1 << 8) 61#define OMAP_TIMER_CTRL_TCM_HIGHTOLOW (0x2 << 8) 62#define OMAP_TIMER_CTRL_TCM_BOTHEDGES (0x3 << 8) 63#define OMAP_TIMER_CTRL_SCPWM (1 << 7) 64#define OMAP_TIMER_CTRL_CE (1 << 6) /* compare enable */ 65#define OMAP_TIMER_CTRL_PRE (1 << 5) /* prescaler enable */ 66#define OMAP_TIMER_CTRL_PTV_SHIFT 2 /* how much to shift the prescaler value */ 67#define OMAP_TIMER_CTRL_AR (1 << 1) /* auto-reload enable */ 68#define OMAP_TIMER_CTRL_ST (1 << 0) /* start timer */ 69 70struct omap_dm_timer { 71 unsigned long phys_base; 72 int irq; 73#ifdef CONFIG_ARCH_OMAP2 74 struct clk *iclk, *fclk; 75#endif 76 void __iomem *io_base; 77 unsigned reserved:1; 78 unsigned enabled:1; 79}; 80 81#ifdef CONFIG_ARCH_OMAP1 82 83#define omap_dm_clk_enable(x) 84#define omap_dm_clk_disable(x) 85 86static struct omap_dm_timer dm_timers[] = { 87 { .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 }, 88 { .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 }, 89 { .phys_base = 0xfffb2400, .irq = INT_1610_GPTIMER3 }, 90 { .phys_base = 0xfffb2c00, .irq = INT_1610_GPTIMER4 }, 91 { .phys_base = 0xfffb3400, .irq = INT_1610_GPTIMER5 }, 92 { .phys_base = 0xfffb3c00, .irq = INT_1610_GPTIMER6 }, 93 { .phys_base = 0xfffb7400, .irq = INT_1610_GPTIMER7 }, 94 { .phys_base = 0xfffbd400, .irq = INT_1610_GPTIMER8 }, 95}; 96 97#elif defined(CONFIG_ARCH_OMAP2) 98 99#define omap_dm_clk_enable(x) clk_enable(x) 100#define omap_dm_clk_disable(x) clk_disable(x) 101 102static struct omap_dm_timer dm_timers[] = { 103 { .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 }, 104 { .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 }, 105 { .phys_base = 0x48078000, .irq = INT_24XX_GPTIMER3 }, 106 { .phys_base = 0x4807a000, .irq = INT_24XX_GPTIMER4 }, 107 { .phys_base = 0x4807c000, .irq = INT_24XX_GPTIMER5 }, 108 { .phys_base = 0x4807e000, .irq = INT_24XX_GPTIMER6 }, 109 { .phys_base = 0x48080000, .irq = INT_24XX_GPTIMER7 }, 110 { .phys_base = 0x48082000, .irq = INT_24XX_GPTIMER8 }, 111 { .phys_base = 0x48084000, .irq = INT_24XX_GPTIMER9 }, 112 { .phys_base = 0x48086000, .irq = INT_24XX_GPTIMER10 }, 113 { .phys_base = 0x48088000, .irq = INT_24XX_GPTIMER11 }, 114 { .phys_base = 0x4808a000, .irq = INT_24XX_GPTIMER12 }, 115}; 116 117static const char *dm_source_names[] = { 118 "sys_ck", 119 "func_32k_ck", 120 "alt_ck" 121}; 122 123static struct clk *dm_source_clocks[3]; 124 125#else 126 127#error OMAP architecture not supported! 128 129#endif 130 131static const int dm_timer_count = ARRAY_SIZE(dm_timers); 132static spinlock_t dm_timer_lock; 133 134static inline u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg) 135{ 136 return readl(timer->io_base + reg); 137} 138 139static void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value) 140{ 141 writel(value, timer->io_base + reg); 142 while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG)) 143 ; 144} 145 146static void omap_dm_timer_wait_for_reset(struct omap_dm_timer *timer) 147{ 148 int c; 149 150 c = 0; 151 while (!(omap_dm_timer_read_reg(timer, OMAP_TIMER_SYS_STAT_REG) & 1)) { 152 c++; 153 if (c > 100000) { 154 printk(KERN_ERR "Timer failed to reset\n"); 155 return; 156 } 157 } 158} 159 160static void omap_dm_timer_reset(struct omap_dm_timer *timer) 161{ 162 u32 l; 163 164 if (!cpu_class_is_omap2() || timer != &dm_timers[0]) { 165 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06); 166 omap_dm_timer_wait_for_reset(timer); 167 } 168 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ); 169 170 /* Set to smart-idle mode */ 171 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG); 172 l |= 0x02 << 3; 173 174 if (cpu_class_is_omap2() && timer == &dm_timers[0]) { 175 /* Enable wake-up only for GPT1 on OMAP2 CPUs*/ 176 l |= 1 << 2; 177 /* Non-posted mode */ 178 omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0); 179 } 180 omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l); 181} 182 183static void omap_dm_timer_prepare(struct omap_dm_timer *timer) 184{ 185 omap_dm_timer_enable(timer); 186 omap_dm_timer_reset(timer); 187} 188 189struct omap_dm_timer *omap_dm_timer_request(void) 190{ 191 struct omap_dm_timer *timer = NULL; 192 unsigned long flags; 193 int i; 194 195 spin_lock_irqsave(&dm_timer_lock, flags); 196 for (i = 0; i < dm_timer_count; i++) { 197 if (dm_timers[i].reserved) 198 continue; 199 200 timer = &dm_timers[i]; 201 timer->reserved = 1; 202 break; 203 } 204 spin_unlock_irqrestore(&dm_timer_lock, flags); 205 206 if (timer != NULL) 207 omap_dm_timer_prepare(timer); 208 209 return timer; 210} 211 212struct omap_dm_timer *omap_dm_timer_request_specific(int id) 213{ 214 struct omap_dm_timer *timer; 215 unsigned long flags; 216 217 spin_lock_irqsave(&dm_timer_lock, flags); 218 if (id <= 0 || id > dm_timer_count || dm_timers[id-1].reserved) { 219 spin_unlock_irqrestore(&dm_timer_lock, flags); 220 printk("BUG: warning at %s:%d/%s(): unable to get timer %d\n", 221 __FILE__, __LINE__, __FUNCTION__, id); 222 dump_stack(); 223 return NULL; 224 } 225 226 timer = &dm_timers[id-1]; 227 timer->reserved = 1; 228 spin_unlock_irqrestore(&dm_timer_lock, flags); 229 230 omap_dm_timer_prepare(timer); 231 232 return timer; 233} 234 235void omap_dm_timer_free(struct omap_dm_timer *timer) 236{ 237 omap_dm_timer_enable(timer); 238 omap_dm_timer_reset(timer); 239 omap_dm_timer_disable(timer); 240 241 WARN_ON(!timer->reserved); 242 timer->reserved = 0; 243} 244 245void omap_dm_timer_enable(struct omap_dm_timer *timer) 246{ 247 if (timer->enabled) 248 return; 249 250 omap_dm_clk_enable(timer->fclk); 251 omap_dm_clk_enable(timer->iclk); 252 253 timer->enabled = 1; 254} 255 256void omap_dm_timer_disable(struct omap_dm_timer *timer) 257{ 258 if (!timer->enabled) 259 return; 260 261 omap_dm_clk_disable(timer->iclk); 262 omap_dm_clk_disable(timer->fclk); 263 264 timer->enabled = 0; 265} 266 267int omap_dm_timer_get_irq(struct omap_dm_timer *timer) 268{ 269 return timer->irq; 270} 271 272#if defined(CONFIG_ARCH_OMAP1) 273 274struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) 275{ 276 BUG(); 277} 278 279/** 280 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR 281 * @inputmask: current value of idlect mask 282 */ 283__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) 284{ 285 int i; 286 287 /* If ARMXOR cannot be idled this function call is unnecessary */ 288 if (!(inputmask & (1 << 1))) 289 return inputmask; 290 291 /* If any active timer is using ARMXOR return modified mask */ 292 for (i = 0; i < dm_timer_count; i++) { 293 u32 l; 294 295 l = omap_dm_timer_read_reg(&dm_timers[i], OMAP_TIMER_CTRL_REG); 296 if (l & OMAP_TIMER_CTRL_ST) { 297 if (((omap_readl(MOD_CONF_CTRL_1) >> (i * 2)) & 0x03) == 0) 298 inputmask &= ~(1 << 1); 299 else 300 inputmask &= ~(1 << 2); 301 } 302 } 303 304 return inputmask; 305} 306 307#elif defined(CONFIG_ARCH_OMAP2) 308 309struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer) 310{ 311 return timer->fclk; 312} 313 314__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask) 315{ 316 BUG(); 317 318 return 0; 319} 320 321#endif 322 323void omap_dm_timer_trigger(struct omap_dm_timer *timer) 324{ 325 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); 326} 327 328void omap_dm_timer_start(struct omap_dm_timer *timer) 329{ 330 u32 l; 331 332 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 333 if (!(l & OMAP_TIMER_CTRL_ST)) { 334 l |= OMAP_TIMER_CTRL_ST; 335 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 336 } 337} 338 339void omap_dm_timer_stop(struct omap_dm_timer *timer) 340{ 341 u32 l; 342 343 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 344 if (l & OMAP_TIMER_CTRL_ST) { 345 l &= ~0x1; 346 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 347 } 348} 349 350#ifdef CONFIG_ARCH_OMAP1 351 352void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) 353{ 354 int n = (timer - dm_timers) << 1; 355 u32 l; 356 357 l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n); 358 l |= source << n; 359 omap_writel(l, MOD_CONF_CTRL_1); 360} 361 362#else 363 364void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source) 365{ 366 if (source < 0 || source >= 3) 367 return; 368 369 clk_disable(timer->fclk); 370 clk_set_parent(timer->fclk, dm_source_clocks[source]); 371 clk_enable(timer->fclk); 372 373 /* When the functional clock disappears, too quick writes seem to 374 * cause an abort. */ 375 __delay(150000); 376} 377 378#endif 379 380void omap_dm_timer_set_load(struct omap_dm_timer *timer, int autoreload, 381 unsigned int load) 382{ 383 u32 l; 384 385 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 386 if (autoreload) 387 l |= OMAP_TIMER_CTRL_AR; 388 else 389 l &= ~OMAP_TIMER_CTRL_AR; 390 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 391 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load); 392 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 0); 393} 394 395void omap_dm_timer_set_match(struct omap_dm_timer *timer, int enable, 396 unsigned int match) 397{ 398 u32 l; 399 400 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 401 if (enable) 402 l |= OMAP_TIMER_CTRL_CE; 403 else 404 l &= ~OMAP_TIMER_CTRL_CE; 405 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 406 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match); 407} 408 409 410void omap_dm_timer_set_pwm(struct omap_dm_timer *timer, int def_on, 411 int toggle, int trigger) 412{ 413 u32 l; 414 415 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 416 l &= ~(OMAP_TIMER_CTRL_GPOCFG | OMAP_TIMER_CTRL_SCPWM | 417 OMAP_TIMER_CTRL_PT | (0x03 << 10)); 418 if (def_on) 419 l |= OMAP_TIMER_CTRL_SCPWM; 420 if (toggle) 421 l |= OMAP_TIMER_CTRL_PT; 422 l |= trigger << 10; 423 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 424} 425 426void omap_dm_timer_set_prescaler(struct omap_dm_timer *timer, int prescaler) 427{ 428 u32 l; 429 430 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG); 431 l &= ~(OMAP_TIMER_CTRL_PRE | (0x07 << 2)); 432 if (prescaler >= 0x00 && prescaler <= 0x07) { 433 l |= OMAP_TIMER_CTRL_PRE; 434 l |= prescaler << 2; 435 } 436 omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l); 437} 438 439void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer, 440 unsigned int value) 441{ 442 omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value); 443 omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value); 444} 445 446unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer) 447{ 448 unsigned int l; 449 450 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG); 451 452 return l; 453} 454 455void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value) 456{ 457 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value); 458} 459 460unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer) 461{ 462 unsigned int l; 463 464 l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG); 465 466 return l; 467} 468 469void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value) 470{ 471 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value); 472} 473 474int omap_dm_timers_active(void) 475{ 476 int i; 477 478 for (i = 0; i < dm_timer_count; i++) { 479 struct omap_dm_timer *timer; 480 481 timer = &dm_timers[i]; 482 483 if (!timer->enabled) 484 continue; 485 486 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) & 487 OMAP_TIMER_CTRL_ST) { 488 return 1; 489 } 490 } 491 return 0; 492} 493 494int omap_dm_timer_init(void) 495{ 496 struct omap_dm_timer *timer; 497 int i; 498 499 if (!(cpu_is_omap16xx() || cpu_is_omap24xx())) 500 return -ENODEV; 501 502 spin_lock_init(&dm_timer_lock); 503#ifdef CONFIG_ARCH_OMAP2 504 for (i = 0; i < ARRAY_SIZE(dm_source_names); i++) { 505 dm_source_clocks[i] = clk_get(NULL, dm_source_names[i]); 506 BUG_ON(dm_source_clocks[i] == NULL); 507 } 508#endif 509 if (cpu_is_omap243x()) 510 dm_timers[0].phys_base = 0x49018000; 511 512 for (i = 0; i < dm_timer_count; i++) { 513#ifdef CONFIG_ARCH_OMAP2 514 char clk_name[16]; 515#endif 516 517 timer = &dm_timers[i]; 518 timer->io_base = (void __iomem *) io_p2v(timer->phys_base); 519#ifdef CONFIG_ARCH_OMAP2 520 sprintf(clk_name, "gpt%d_ick", i + 1); 521 timer->iclk = clk_get(NULL, clk_name); 522 sprintf(clk_name, "gpt%d_fck", i + 1); 523 timer->fclk = clk_get(NULL, clk_name); 524#endif 525 } 526 527 return 0; 528} 529