| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * apb_timer.c: Driver for Langwell APB timers |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * (C) Copyright 2009 Intel Corporation |
|---|
| 5 | 6 | * Author: Jacob Pan (jacob.jun.pan@intel.com) |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public License |
|---|
| 9 | | - * as published by the Free Software Foundation; version 2 |
|---|
| 10 | | - * of the License. |
|---|
| 11 | 7 | * |
|---|
| 12 | 8 | * Note: |
|---|
| 13 | 9 | * Langwell is the south complex of Intel Moorestown MID platform. There are |
|---|
| .. | .. |
|---|
| 99 | 95 | printk(KERN_WARNING "No timer base from SFI, use default\n"); |
|---|
| 100 | 96 | apbt_address = APBT_DEFAULT_BASE; |
|---|
| 101 | 97 | } |
|---|
| 102 | | - apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); |
|---|
| 98 | + apbt_virt_address = ioremap(apbt_address, APBT_MMAP_SIZE); |
|---|
| 103 | 99 | if (!apbt_virt_address) { |
|---|
| 104 | 100 | pr_debug("Failed mapping APBT phy address at %lu\n",\ |
|---|
| 105 | 101 | (unsigned long)apbt_address); |
|---|
| .. | .. |
|---|
| 348 | 344 | apbt_clear_mapping(); |
|---|
| 349 | 345 | apb_timer_block_enabled = 0; |
|---|
| 350 | 346 | panic("failed to enable APB timer\n"); |
|---|
| 351 | | -} |
|---|
| 352 | | - |
|---|
| 353 | | -/* called before apb_timer_enable, use early map */ |
|---|
| 354 | | -unsigned long apbt_quick_calibrate(void) |
|---|
| 355 | | -{ |
|---|
| 356 | | - int i, scale; |
|---|
| 357 | | - u64 old, new; |
|---|
| 358 | | - u64 t1, t2; |
|---|
| 359 | | - unsigned long khz = 0; |
|---|
| 360 | | - u32 loop, shift; |
|---|
| 361 | | - |
|---|
| 362 | | - apbt_set_mapping(); |
|---|
| 363 | | - dw_apb_clocksource_start(clocksource_apbt); |
|---|
| 364 | | - |
|---|
| 365 | | - /* check if the timer can count down, otherwise return */ |
|---|
| 366 | | - old = dw_apb_clocksource_read(clocksource_apbt); |
|---|
| 367 | | - i = 10000; |
|---|
| 368 | | - while (--i) { |
|---|
| 369 | | - if (old != dw_apb_clocksource_read(clocksource_apbt)) |
|---|
| 370 | | - break; |
|---|
| 371 | | - } |
|---|
| 372 | | - if (!i) |
|---|
| 373 | | - goto failed; |
|---|
| 374 | | - |
|---|
| 375 | | - /* count 16 ms */ |
|---|
| 376 | | - loop = (apbt_freq / 1000) << 4; |
|---|
| 377 | | - |
|---|
| 378 | | - /* restart the timer to ensure it won't get to 0 in the calibration */ |
|---|
| 379 | | - dw_apb_clocksource_start(clocksource_apbt); |
|---|
| 380 | | - |
|---|
| 381 | | - old = dw_apb_clocksource_read(clocksource_apbt); |
|---|
| 382 | | - old += loop; |
|---|
| 383 | | - |
|---|
| 384 | | - t1 = rdtsc(); |
|---|
| 385 | | - |
|---|
| 386 | | - do { |
|---|
| 387 | | - new = dw_apb_clocksource_read(clocksource_apbt); |
|---|
| 388 | | - } while (new < old); |
|---|
| 389 | | - |
|---|
| 390 | | - t2 = rdtsc(); |
|---|
| 391 | | - |
|---|
| 392 | | - shift = 5; |
|---|
| 393 | | - if (unlikely(loop >> shift == 0)) { |
|---|
| 394 | | - printk(KERN_INFO |
|---|
| 395 | | - "APBT TSC calibration failed, not enough resolution\n"); |
|---|
| 396 | | - return 0; |
|---|
| 397 | | - } |
|---|
| 398 | | - scale = (int)div_u64((t2 - t1), loop >> shift); |
|---|
| 399 | | - khz = (scale * (apbt_freq / 1000)) >> shift; |
|---|
| 400 | | - printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); |
|---|
| 401 | | - return khz; |
|---|
| 402 | | -failed: |
|---|
| 403 | | - return 0; |
|---|
| 404 | 347 | } |
|---|