diff options
| -rw-r--r-- | arch/x86/Kconfig | 1 | ||||
| -rw-r--r-- | arch/x86/include/asm/apb_timer.h | 22 | ||||
| -rw-r--r-- | arch/x86/kernel/apb_timer.c | 409 | ||||
| -rw-r--r-- | drivers/clocksource/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/clocksource/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clocksource/dw_apb_timer.c | 401 | ||||
| -rw-r--r-- | include/linux/dw_apb_timer.h | 56 |
7 files changed, 533 insertions, 360 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 5f60ea190d5b..c3e03e46bc64 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -623,6 +623,7 @@ config HPET_EMULATE_RTC | |||
| 623 | config APB_TIMER | 623 | config APB_TIMER |
| 624 | def_bool y if MRST | 624 | def_bool y if MRST |
| 625 | prompt "Langwell APB Timer Support" if X86_MRST | 625 | prompt "Langwell APB Timer Support" if X86_MRST |
| 626 | select DW_APB_TIMER | ||
| 626 | help | 627 | help |
| 627 | APB timer is the replacement for 8254, HPET on X86 MID platforms. | 628 | APB timer is the replacement for 8254, HPET on X86 MID platforms. |
| 628 | The APBT provides a stable time base on SMP | 629 | The APBT provides a stable time base on SMP |
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h index 082cf8184935..0acbac299e49 100644 --- a/arch/x86/include/asm/apb_timer.h +++ b/arch/x86/include/asm/apb_timer.h | |||
| @@ -18,24 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | #ifdef CONFIG_APB_TIMER | 19 | #ifdef CONFIG_APB_TIMER |
| 20 | 20 | ||
| 21 | /* Langwell DW APB timer registers */ | ||
| 22 | #define APBTMR_N_LOAD_COUNT 0x00 | ||
| 23 | #define APBTMR_N_CURRENT_VALUE 0x04 | ||
| 24 | #define APBTMR_N_CONTROL 0x08 | ||
| 25 | #define APBTMR_N_EOI 0x0c | ||
| 26 | #define APBTMR_N_INT_STATUS 0x10 | ||
| 27 | |||
| 28 | #define APBTMRS_INT_STATUS 0xa0 | ||
| 29 | #define APBTMRS_EOI 0xa4 | ||
| 30 | #define APBTMRS_RAW_INT_STATUS 0xa8 | ||
| 31 | #define APBTMRS_COMP_VERSION 0xac | ||
| 32 | #define APBTMRS_REG_SIZE 0x14 | ||
| 33 | |||
| 34 | /* register bits */ | ||
| 35 | #define APBTMR_CONTROL_ENABLE (1<<0) | ||
| 36 | #define APBTMR_CONTROL_MODE_PERIODIC (1<<1) /*1: periodic 0:free running */ | ||
| 37 | #define APBTMR_CONTROL_INT (1<<2) | ||
| 38 | |||
| 39 | /* default memory mapped register base */ | 21 | /* default memory mapped register base */ |
| 40 | #define LNW_SCU_ADDR 0xFF100000 | 22 | #define LNW_SCU_ADDR 0xFF100000 |
| 41 | #define LNW_EXT_TIMER_OFFSET 0x1B800 | 23 | #define LNW_EXT_TIMER_OFFSET 0x1B800 |
| @@ -43,8 +25,8 @@ | |||
| 43 | #define LNW_EXT_TIMER_PGOFFSET 0x800 | 25 | #define LNW_EXT_TIMER_PGOFFSET 0x800 |
| 44 | 26 | ||
| 45 | /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ | 27 | /* APBT clock speed range from PCLK to fabric base, 25-100MHz */ |
| 46 | #define APBT_MAX_FREQ 50 | 28 | #define APBT_MAX_FREQ 50000000 |
| 47 | #define APBT_MIN_FREQ 1 | 29 | #define APBT_MIN_FREQ 1000000 |
| 48 | #define APBT_MMAP_SIZE 1024 | 30 | #define APBT_MMAP_SIZE 1024 |
| 49 | 31 | ||
| 50 | #define APBT_DEV_USED 1 | 32 | #define APBT_DEV_USED 1 |
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c index 2b6630d75e17..afdc3f756dea 100644 --- a/arch/x86/kernel/apb_timer.c +++ b/arch/x86/kernel/apb_timer.c | |||
| @@ -27,15 +27,12 @@ | |||
| 27 | * timer, but by default APB timer has higher rating than local APIC timers. | 27 | * timer, but by default APB timer has higher rating than local APIC timers. |
| 28 | */ | 28 | */ |
| 29 | 29 | ||
| 30 | #include <linux/clocksource.h> | ||
| 31 | #include <linux/clockchips.h> | ||
| 32 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
| 31 | #include <linux/dw_apb_timer.h> | ||
| 33 | #include <linux/errno.h> | 32 | #include <linux/errno.h> |
| 34 | #include <linux/init.h> | 33 | #include <linux/init.h> |
| 35 | #include <linux/sysdev.h> | ||
| 36 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 37 | #include <linux/pm.h> | 35 | #include <linux/pm.h> |
| 38 | #include <linux/pci.h> | ||
| 39 | #include <linux/sfi.h> | 36 | #include <linux/sfi.h> |
| 40 | #include <linux/interrupt.h> | 37 | #include <linux/interrupt.h> |
| 41 | #include <linux/cpu.h> | 38 | #include <linux/cpu.h> |
| @@ -46,75 +43,46 @@ | |||
| 46 | #include <asm/mrst.h> | 43 | #include <asm/mrst.h> |
| 47 | #include <asm/time.h> | 44 | #include <asm/time.h> |
| 48 | 45 | ||
| 49 | #define APBT_MASK CLOCKSOURCE_MASK(32) | ||
| 50 | #define APBT_SHIFT 22 | ||
| 51 | #define APBT_CLOCKEVENT_RATING 110 | 46 | #define APBT_CLOCKEVENT_RATING 110 |
| 52 | #define APBT_CLOCKSOURCE_RATING 250 | 47 | #define APBT_CLOCKSOURCE_RATING 250 |
| 53 | #define APBT_MIN_DELTA_USEC 200 | ||
| 54 | 48 | ||
| 55 | #define EVT_TO_APBT_DEV(evt) container_of(evt, struct apbt_dev, evt) | ||
| 56 | #define APBT_CLOCKEVENT0_NUM (0) | 49 | #define APBT_CLOCKEVENT0_NUM (0) |
| 57 | #define APBT_CLOCKEVENT1_NUM (1) | ||
| 58 | #define APBT_CLOCKSOURCE_NUM (2) | 50 | #define APBT_CLOCKSOURCE_NUM (2) |
| 59 | 51 | ||
| 60 | static unsigned long apbt_address; | 52 | static phys_addr_t apbt_address; |
| 61 | static int apb_timer_block_enabled; | 53 | static int apb_timer_block_enabled; |
| 62 | static void __iomem *apbt_virt_address; | 54 | static void __iomem *apbt_virt_address; |
| 63 | static int phy_cs_timer_id; | ||
| 64 | 55 | ||
| 65 | /* | 56 | /* |
| 66 | * Common DW APB timer info | 57 | * Common DW APB timer info |
| 67 | */ | 58 | */ |
| 68 | static uint64_t apbt_freq; | 59 | static unsigned long apbt_freq; |
| 69 | |||
| 70 | static void apbt_set_mode(enum clock_event_mode mode, | ||
| 71 | struct clock_event_device *evt); | ||
| 72 | static int apbt_next_event(unsigned long delta, | ||
| 73 | struct clock_event_device *evt); | ||
| 74 | static cycle_t apbt_read_clocksource(struct clocksource *cs); | ||
| 75 | static void apbt_restart_clocksource(struct clocksource *cs); | ||
| 76 | 60 | ||
| 77 | struct apbt_dev { | 61 | struct apbt_dev { |
| 78 | struct clock_event_device evt; | 62 | struct dw_apb_clock_event_device *timer; |
| 79 | unsigned int num; | 63 | unsigned int num; |
| 80 | int cpu; | 64 | int cpu; |
| 81 | unsigned int irq; | 65 | unsigned int irq; |
| 82 | unsigned int tick; | 66 | char name[10]; |
| 83 | unsigned int count; | ||
| 84 | unsigned int flags; | ||
| 85 | char name[10]; | ||
| 86 | }; | 67 | }; |
| 87 | 68 | ||
| 88 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); | 69 | static struct dw_apb_clocksource *clocksource_apbt; |
| 89 | 70 | ||
| 90 | #ifdef CONFIG_SMP | 71 | static inline void __iomem *adev_virt_addr(struct apbt_dev *adev) |
| 91 | static unsigned int apbt_num_timers_used; | ||
| 92 | static struct apbt_dev *apbt_devs; | ||
| 93 | #endif | ||
| 94 | |||
| 95 | static inline unsigned long apbt_readl_reg(unsigned long a) | ||
| 96 | { | 72 | { |
| 97 | return readl(apbt_virt_address + a); | 73 | return apbt_virt_address + adev->num * APBTMRS_REG_SIZE; |
| 98 | } | 74 | } |
| 99 | 75 | ||
| 100 | static inline void apbt_writel_reg(unsigned long d, unsigned long a) | 76 | static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev); |
| 101 | { | ||
| 102 | writel(d, apbt_virt_address + a); | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline unsigned long apbt_readl(int n, unsigned long a) | ||
| 106 | { | ||
| 107 | return readl(apbt_virt_address + a + n * APBTMRS_REG_SIZE); | ||
| 108 | } | ||
| 109 | 77 | ||
| 110 | static inline void apbt_writel(int n, unsigned long d, unsigned long a) | 78 | #ifdef CONFIG_SMP |
| 111 | { | 79 | static unsigned int apbt_num_timers_used; |
| 112 | writel(d, apbt_virt_address + a + n * APBTMRS_REG_SIZE); | 80 | #endif |
| 113 | } | ||
| 114 | 81 | ||
| 115 | static inline void apbt_set_mapping(void) | 82 | static inline void apbt_set_mapping(void) |
| 116 | { | 83 | { |
| 117 | struct sfi_timer_table_entry *mtmr; | 84 | struct sfi_timer_table_entry *mtmr; |
| 85 | int phy_cs_timer_id = 0; | ||
| 118 | 86 | ||
| 119 | if (apbt_virt_address) { | 87 | if (apbt_virt_address) { |
| 120 | pr_debug("APBT base already mapped\n"); | 88 | pr_debug("APBT base already mapped\n"); |
| @@ -126,21 +94,18 @@ static inline void apbt_set_mapping(void) | |||
| 126 | APBT_CLOCKEVENT0_NUM); | 94 | APBT_CLOCKEVENT0_NUM); |
| 127 | return; | 95 | return; |
| 128 | } | 96 | } |
| 129 | apbt_address = (unsigned long)mtmr->phys_addr; | 97 | apbt_address = (phys_addr_t)mtmr->phys_addr; |
| 130 | if (!apbt_address) { | 98 | if (!apbt_address) { |
| 131 | printk(KERN_WARNING "No timer base from SFI, use default\n"); | 99 | printk(KERN_WARNING "No timer base from SFI, use default\n"); |
| 132 | apbt_address = APBT_DEFAULT_BASE; | 100 | apbt_address = APBT_DEFAULT_BASE; |
| 133 | } | 101 | } |
| 134 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); | 102 | apbt_virt_address = ioremap_nocache(apbt_address, APBT_MMAP_SIZE); |
| 135 | if (apbt_virt_address) { | 103 | if (!apbt_virt_address) { |
| 136 | pr_debug("Mapped APBT physical addr %p at virtual addr %p\n",\ | 104 | pr_debug("Failed mapping APBT phy address at %lu\n",\ |
| 137 | (void *)apbt_address, (void *)apbt_virt_address); | 105 | (unsigned long)apbt_address); |
| 138 | } else { | ||
| 139 | pr_debug("Failed mapping APBT phy address at %p\n",\ | ||
| 140 | (void *)apbt_address); | ||
| 141 | goto panic_noapbt; | 106 | goto panic_noapbt; |
| 142 | } | 107 | } |
| 143 | apbt_freq = mtmr->freq_hz / USEC_PER_SEC; | 108 | apbt_freq = mtmr->freq_hz; |
| 144 | sfi_free_mtmr(mtmr); | 109 | sfi_free_mtmr(mtmr); |
| 145 | 110 | ||
| 146 | /* Now figure out the physical timer id for clocksource device */ | 111 | /* Now figure out the physical timer id for clocksource device */ |
| @@ -149,9 +114,14 @@ static inline void apbt_set_mapping(void) | |||
| 149 | goto panic_noapbt; | 114 | goto panic_noapbt; |
| 150 | 115 | ||
| 151 | /* Now figure out the physical timer id */ | 116 | /* Now figure out the physical timer id */ |
| 152 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) | 117 | pr_debug("Use timer %d for clocksource\n", |
| 153 | / APBTMRS_REG_SIZE; | 118 | (int)(mtmr->phys_addr & 0xff) / APBTMRS_REG_SIZE); |
| 154 | pr_debug("Use timer %d for clocksource\n", phy_cs_timer_id); | 119 | phy_cs_timer_id = (unsigned int)(mtmr->phys_addr & 0xff) / |
| 120 | APBTMRS_REG_SIZE; | ||
| 121 | |||
| 122 | clocksource_apbt = dw_apb_clocksource_init(APBT_CLOCKSOURCE_RATING, | ||
| 123 | "apbt0", apbt_virt_address + phy_cs_timer_id * | ||
| 124 | APBTMRS_REG_SIZE, apbt_freq); | ||
| 155 | return; | 125 | return; |
| 156 | 126 | ||
| 157 | panic_noapbt: | 127 | panic_noapbt: |
| @@ -173,82 +143,6 @@ static inline int is_apbt_capable(void) | |||
| 173 | return apbt_virt_address ? 1 : 0; | 143 | return apbt_virt_address ? 1 : 0; |
| 174 | } | 144 | } |
| 175 | 145 | ||
| 176 | static struct clocksource clocksource_apbt = { | ||
| 177 | .name = "apbt", | ||
| 178 | .rating = APBT_CLOCKSOURCE_RATING, | ||
| 179 | .read = apbt_read_clocksource, | ||
| 180 | .mask = APBT_MASK, | ||
| 181 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 182 | .resume = apbt_restart_clocksource, | ||
| 183 | }; | ||
| 184 | |||
| 185 | /* boot APB clock event device */ | ||
| 186 | static struct clock_event_device apbt_clockevent = { | ||
| 187 | .name = "apbt0", | ||
| 188 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 189 | .set_mode = apbt_set_mode, | ||
| 190 | .set_next_event = apbt_next_event, | ||
| 191 | .shift = APBT_SHIFT, | ||
| 192 | .irq = 0, | ||
| 193 | .rating = APBT_CLOCKEVENT_RATING, | ||
| 194 | }; | ||
| 195 | |||
| 196 | /* | ||
| 197 | * start count down from 0xffff_ffff. this is done by toggling the enable bit | ||
| 198 | * then load initial load count to ~0. | ||
| 199 | */ | ||
| 200 | static void apbt_start_counter(int n) | ||
| 201 | { | ||
| 202 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 203 | |||
| 204 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 205 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 206 | apbt_writel(n, ~0, APBTMR_N_LOAD_COUNT); | ||
| 207 | /* enable, mask interrupt */ | ||
| 208 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 209 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
| 210 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 211 | /* read it once to get cached counter value initialized */ | ||
| 212 | apbt_read_clocksource(&clocksource_apbt); | ||
| 213 | } | ||
| 214 | |||
| 215 | static irqreturn_t apbt_interrupt_handler(int irq, void *data) | ||
| 216 | { | ||
| 217 | struct apbt_dev *dev = (struct apbt_dev *)data; | ||
| 218 | struct clock_event_device *aevt = &dev->evt; | ||
| 219 | |||
| 220 | if (!aevt->event_handler) { | ||
| 221 | printk(KERN_INFO "Spurious APBT timer interrupt on %d\n", | ||
| 222 | dev->num); | ||
| 223 | return IRQ_NONE; | ||
| 224 | } | ||
| 225 | aevt->event_handler(aevt); | ||
| 226 | return IRQ_HANDLED; | ||
| 227 | } | ||
| 228 | |||
| 229 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
| 230 | { | ||
| 231 | apbt_start_counter(phy_cs_timer_id); | ||
| 232 | } | ||
| 233 | |||
| 234 | static void apbt_enable_int(int n) | ||
| 235 | { | ||
| 236 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 237 | /* clear pending intr */ | ||
| 238 | apbt_readl(n, APBTMR_N_EOI); | ||
| 239 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 240 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 241 | } | ||
| 242 | |||
| 243 | static void apbt_disable_int(int n) | ||
| 244 | { | ||
| 245 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 246 | |||
| 247 | ctrl |= APBTMR_CONTROL_INT; | ||
| 248 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 249 | } | ||
| 250 | |||
| 251 | |||
| 252 | static int __init apbt_clockevent_register(void) | 146 | static int __init apbt_clockevent_register(void) |
| 253 | { | 147 | { |
| 254 | struct sfi_timer_table_entry *mtmr; | 148 | struct sfi_timer_table_entry *mtmr; |
| @@ -261,45 +155,21 @@ static int __init apbt_clockevent_register(void) | |||
| 261 | return -ENODEV; | 155 | return -ENODEV; |
| 262 | } | 156 | } |
| 263 | 157 | ||
| 264 | /* | ||
| 265 | * We need to calculate the scaled math multiplication factor for | ||
| 266 | * nanosecond to apbt tick conversion. | ||
| 267 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
| 268 | */ | ||
| 269 | apbt_clockevent.mult = div_sc((unsigned long) mtmr->freq_hz | ||
| 270 | , NSEC_PER_SEC, APBT_SHIFT); | ||
| 271 | |||
| 272 | /* Calculate the min / max delta */ | ||
| 273 | apbt_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF, | ||
| 274 | &apbt_clockevent); | ||
| 275 | apbt_clockevent.min_delta_ns = clockevent_delta2ns( | ||
| 276 | APBT_MIN_DELTA_USEC*apbt_freq, | ||
| 277 | &apbt_clockevent); | ||
| 278 | /* | ||
| 279 | * Start apbt with the boot cpu mask and make it | ||
| 280 | * global if not used for per cpu timer. | ||
| 281 | */ | ||
| 282 | apbt_clockevent.cpumask = cpumask_of(smp_processor_id()); | ||
| 283 | adev->num = smp_processor_id(); | 158 | adev->num = smp_processor_id(); |
| 284 | memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device)); | 159 | adev->timer = dw_apb_clockevent_init(smp_processor_id(), "apbt0", |
| 160 | mrst_timer_options == MRST_TIMER_LAPIC_APBT ? | ||
| 161 | APBT_CLOCKEVENT_RATING - 100 : APBT_CLOCKEVENT_RATING, | ||
| 162 | adev_virt_addr(adev), 0, apbt_freq); | ||
| 163 | /* Firmware does EOI handling for us. */ | ||
| 164 | adev->timer->eoi = NULL; | ||
| 285 | 165 | ||
| 286 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { | 166 | if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) { |
| 287 | adev->evt.rating = APBT_CLOCKEVENT_RATING - 100; | 167 | global_clock_event = &adev->timer->ced; |
| 288 | global_clock_event = &adev->evt; | ||
| 289 | printk(KERN_DEBUG "%s clockevent registered as global\n", | 168 | printk(KERN_DEBUG "%s clockevent registered as global\n", |
| 290 | global_clock_event->name); | 169 | global_clock_event->name); |
| 291 | } | 170 | } |
| 292 | 171 | ||
| 293 | if (request_irq(apbt_clockevent.irq, apbt_interrupt_handler, | 172 | dw_apb_clockevent_register(adev->timer); |
| 294 | IRQF_TIMER | IRQF_DISABLED | IRQF_NOBALANCING, | ||
| 295 | apbt_clockevent.name, adev)) { | ||
| 296 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
| 297 | apbt_clockevent.irq); | ||
| 298 | } | ||
| 299 | |||
| 300 | clockevents_register_device(&adev->evt); | ||
| 301 | /* Start APBT 0 interrupts */ | ||
| 302 | apbt_enable_int(APBT_CLOCKEVENT0_NUM); | ||
| 303 | 173 | ||
| 304 | sfi_free_mtmr(mtmr); | 174 | sfi_free_mtmr(mtmr); |
| 305 | return 0; | 175 | return 0; |
| @@ -317,52 +187,34 @@ static void apbt_setup_irq(struct apbt_dev *adev) | |||
| 317 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); | 187 | irq_set_affinity(adev->irq, cpumask_of(adev->cpu)); |
| 318 | /* APB timer irqs are set up as mp_irqs, timer is edge type */ | 188 | /* APB timer irqs are set up as mp_irqs, timer is edge type */ |
| 319 | __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); | 189 | __irq_set_handler(adev->irq, handle_edge_irq, 0, "edge"); |
| 320 | |||
| 321 | if (system_state == SYSTEM_BOOTING) { | ||
| 322 | if (request_irq(adev->irq, apbt_interrupt_handler, | ||
| 323 | IRQF_TIMER | IRQF_DISABLED | | ||
| 324 | IRQF_NOBALANCING, | ||
| 325 | adev->name, adev)) { | ||
| 326 | printk(KERN_ERR "Failed request IRQ for APBT%d\n", | ||
| 327 | adev->num); | ||
| 328 | } | ||
| 329 | } else | ||
| 330 | enable_irq(adev->irq); | ||
| 331 | } | 190 | } |
| 332 | 191 | ||
| 333 | /* Should be called with per cpu */ | 192 | /* Should be called with per cpu */ |
| 334 | void apbt_setup_secondary_clock(void) | 193 | void apbt_setup_secondary_clock(void) |
| 335 | { | 194 | { |
| 336 | struct apbt_dev *adev; | 195 | struct apbt_dev *adev; |
| 337 | struct clock_event_device *aevt; | ||
| 338 | int cpu; | 196 | int cpu; |
| 339 | 197 | ||
| 340 | /* Don't register boot CPU clockevent */ | 198 | /* Don't register boot CPU clockevent */ |
| 341 | cpu = smp_processor_id(); | 199 | cpu = smp_processor_id(); |
| 342 | if (!cpu) | 200 | if (!cpu) |
| 343 | return; | 201 | return; |
| 344 | /* | ||
| 345 | * We need to calculate the scaled math multiplication factor for | ||
| 346 | * nanosecond to apbt tick conversion. | ||
| 347 | * mult = (nsec/cycle)*2^APBT_SHIFT | ||
| 348 | */ | ||
| 349 | printk(KERN_INFO "Init per CPU clockevent %d\n", cpu); | ||
| 350 | adev = &per_cpu(cpu_apbt_dev, cpu); | ||
| 351 | aevt = &adev->evt; | ||
| 352 | 202 | ||
| 353 | memcpy(aevt, &apbt_clockevent, sizeof(*aevt)); | 203 | adev = &__get_cpu_var(cpu_apbt_dev); |
| 354 | aevt->cpumask = cpumask_of(cpu); | 204 | if (!adev->timer) { |
| 355 | aevt->name = adev->name; | 205 | adev->timer = dw_apb_clockevent_init(cpu, adev->name, |
| 356 | aevt->mode = CLOCK_EVT_MODE_UNUSED; | 206 | APBT_CLOCKEVENT_RATING, adev_virt_addr(adev), |
| 207 | adev->irq, apbt_freq); | ||
| 208 | adev->timer->eoi = NULL; | ||
| 209 | } else { | ||
| 210 | dw_apb_clockevent_resume(adev->timer); | ||
| 211 | } | ||
| 357 | 212 | ||
| 358 | printk(KERN_INFO "Registering CPU %d clockevent device %s, mask %08x\n", | 213 | printk(KERN_INFO "Registering CPU %d clockevent device %s, cpu %08x\n", |
| 359 | cpu, aevt->name, *(u32 *)aevt->cpumask); | 214 | cpu, adev->name, adev->cpu); |
| 360 | 215 | ||
| 361 | apbt_setup_irq(adev); | 216 | apbt_setup_irq(adev); |
| 362 | 217 | dw_apb_clockevent_register(adev->timer); | |
| 363 | clockevents_register_device(aevt); | ||
| 364 | |||
| 365 | apbt_enable_int(cpu); | ||
| 366 | 218 | ||
| 367 | return; | 219 | return; |
| 368 | } | 220 | } |
| @@ -385,13 +237,12 @@ static int apbt_cpuhp_notify(struct notifier_block *n, | |||
| 385 | 237 | ||
| 386 | switch (action & 0xf) { | 238 | switch (action & 0xf) { |
| 387 | case CPU_DEAD: | 239 | case CPU_DEAD: |
| 388 | disable_irq(adev->irq); | 240 | dw_apb_clockevent_pause(adev->timer); |
| 389 | apbt_disable_int(cpu); | ||
| 390 | if (system_state == SYSTEM_RUNNING) { | 241 | if (system_state == SYSTEM_RUNNING) { |
| 391 | pr_debug("skipping APBT CPU %lu offline\n", cpu); | 242 | pr_debug("skipping APBT CPU %lu offline\n", cpu); |
| 392 | } else if (adev) { | 243 | } else if (adev) { |
| 393 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); | 244 | pr_debug("APBT clockevent for cpu %lu offline\n", cpu); |
| 394 | free_irq(adev->irq, adev); | 245 | dw_apb_clockevent_stop(adev->timer); |
| 395 | } | 246 | } |
| 396 | break; | 247 | break; |
| 397 | default: | 248 | default: |
| @@ -416,116 +267,16 @@ void apbt_setup_secondary_clock(void) {} | |||
| 416 | 267 | ||
| 417 | #endif /* CONFIG_SMP */ | 268 | #endif /* CONFIG_SMP */ |
| 418 | 269 | ||
| 419 | static void apbt_set_mode(enum clock_event_mode mode, | ||
| 420 | struct clock_event_device *evt) | ||
| 421 | { | ||
| 422 | unsigned long ctrl; | ||
| 423 | uint64_t delta; | ||
| 424 | int timer_num; | ||
| 425 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
| 426 | |||
| 427 | BUG_ON(!apbt_virt_address); | ||
| 428 | |||
| 429 | timer_num = adev->num; | ||
| 430 | pr_debug("%s CPU %d timer %d mode=%d\n", | ||
| 431 | __func__, first_cpu(*evt->cpumask), timer_num, mode); | ||
| 432 | |||
| 433 | switch (mode) { | ||
| 434 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 435 | delta = ((uint64_t)(NSEC_PER_SEC/HZ)) * apbt_clockevent.mult; | ||
| 436 | delta >>= apbt_clockevent.shift; | ||
| 437 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 438 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
| 439 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 440 | /* | ||
| 441 | * DW APB p. 46, have to disable timer before load counter, | ||
| 442 | * may cause sync problem. | ||
| 443 | */ | ||
| 444 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 445 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 446 | udelay(1); | ||
| 447 | pr_debug("Setting clock period %d for HZ %d\n", (int)delta, HZ); | ||
| 448 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
| 449 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 450 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 451 | break; | ||
| 452 | /* APB timer does not have one-shot mode, use free running mode */ | ||
| 453 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 454 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 455 | /* | ||
| 456 | * set free running mode, this mode will let timer reload max | ||
| 457 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
| 458 | * the next event, therefore emulate the one-shot mode. | ||
| 459 | */ | ||
| 460 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 461 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 462 | |||
| 463 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 464 | /* write again to set free running mode */ | ||
| 465 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 466 | |||
| 467 | /* | ||
| 468 | * DW APB p. 46, load counter with all 1s before starting free | ||
| 469 | * running mode. | ||
| 470 | */ | ||
| 471 | apbt_writel(timer_num, ~0, APBTMR_N_LOAD_COUNT); | ||
| 472 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 473 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 474 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 475 | break; | ||
| 476 | |||
| 477 | case CLOCK_EVT_MODE_UNUSED: | ||
| 478 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 479 | apbt_disable_int(timer_num); | ||
| 480 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 481 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 482 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 483 | break; | ||
| 484 | |||
| 485 | case CLOCK_EVT_MODE_RESUME: | ||
| 486 | apbt_enable_int(timer_num); | ||
| 487 | break; | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | static int apbt_next_event(unsigned long delta, | ||
| 492 | struct clock_event_device *evt) | ||
| 493 | { | ||
| 494 | unsigned long ctrl; | ||
| 495 | int timer_num; | ||
| 496 | |||
| 497 | struct apbt_dev *adev = EVT_TO_APBT_DEV(evt); | ||
| 498 | |||
| 499 | timer_num = adev->num; | ||
| 500 | /* Disable timer */ | ||
| 501 | ctrl = apbt_readl(timer_num, APBTMR_N_CONTROL); | ||
| 502 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 503 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 504 | /* write new count */ | ||
| 505 | apbt_writel(timer_num, delta, APBTMR_N_LOAD_COUNT); | ||
| 506 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 507 | apbt_writel(timer_num, ctrl, APBTMR_N_CONTROL); | ||
| 508 | return 0; | ||
| 509 | } | ||
| 510 | |||
| 511 | static cycle_t apbt_read_clocksource(struct clocksource *cs) | ||
| 512 | { | ||
| 513 | unsigned long current_count; | ||
| 514 | |||
| 515 | current_count = apbt_readl(phy_cs_timer_id, APBTMR_N_CURRENT_VALUE); | ||
| 516 | return (cycle_t)~current_count; | ||
| 517 | } | ||
| 518 | |||
| 519 | static int apbt_clocksource_register(void) | 270 | static int apbt_clocksource_register(void) |
| 520 | { | 271 | { |
| 521 | u64 start, now; | 272 | u64 start, now; |
| 522 | cycle_t t1; | 273 | cycle_t t1; |
| 523 | 274 | ||
| 524 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ | 275 | /* Start the counter, use timer 2 as source, timer 0/1 for event */ |
| 525 | apbt_start_counter(phy_cs_timer_id); | 276 | dw_apb_clocksource_start(clocksource_apbt); |
| 526 | 277 | ||
| 527 | /* Verify whether apbt counter works */ | 278 | /* Verify whether apbt counter works */ |
| 528 | t1 = apbt_read_clocksource(&clocksource_apbt); | 279 | t1 = dw_apb_clocksource_read(clocksource_apbt); |
| 529 | rdtscll(start); | 280 | rdtscll(start); |
| 530 | 281 | ||
| 531 | /* | 282 | /* |
| @@ -540,10 +291,10 @@ static int apbt_clocksource_register(void) | |||
| 540 | } while ((now - start) < 200000UL); | 291 | } while ((now - start) < 200000UL); |
| 541 | 292 | ||
| 542 | /* APBT is the only always on clocksource, it has to work! */ | 293 | /* APBT is the only always on clocksource, it has to work! */ |
| 543 | if (t1 == apbt_read_clocksource(&clocksource_apbt)) | 294 | if (t1 == dw_apb_clocksource_read(clocksource_apbt)) |
| 544 | panic("APBT counter not counting. APBT disabled\n"); | 295 | panic("APBT counter not counting. APBT disabled\n"); |
| 545 | 296 | ||
| 546 | clocksource_register_khz(&clocksource_apbt, (u32)apbt_freq*1000); | 297 | dw_apb_clocksource_register(clocksource_apbt); |
| 547 | 298 | ||
| 548 | return 0; | 299 | return 0; |
| 549 | } | 300 | } |
| @@ -567,10 +318,7 @@ void __init apbt_time_init(void) | |||
| 567 | if (apb_timer_block_enabled) | 318 | if (apb_timer_block_enabled) |
| 568 | return; | 319 | return; |
| 569 | apbt_set_mapping(); | 320 | apbt_set_mapping(); |
| 570 | if (apbt_virt_address) { | 321 | if (!apbt_virt_address) |
| 571 | pr_debug("Found APBT version 0x%lx\n",\ | ||
| 572 | apbt_readl_reg(APBTMRS_COMP_VERSION)); | ||
| 573 | } else | ||
| 574 | goto out_noapbt; | 322 | goto out_noapbt; |
| 575 | /* | 323 | /* |
| 576 | * Read the frequency and check for a sane value, for ESL model | 324 | * Read the frequency and check for a sane value, for ESL model |
| @@ -578,7 +326,7 @@ void __init apbt_time_init(void) | |||
| 578 | */ | 326 | */ |
| 579 | 327 | ||
| 580 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { | 328 | if (apbt_freq < APBT_MIN_FREQ || apbt_freq > APBT_MAX_FREQ) { |
| 581 | pr_debug("APBT has invalid freq 0x%llx\n", apbt_freq); | 329 | pr_debug("APBT has invalid freq 0x%lx\n", apbt_freq); |
| 582 | goto out_noapbt; | 330 | goto out_noapbt; |
| 583 | } | 331 | } |
| 584 | if (apbt_clocksource_register()) { | 332 | if (apbt_clocksource_register()) { |
| @@ -604,30 +352,20 @@ void __init apbt_time_init(void) | |||
| 604 | } else { | 352 | } else { |
| 605 | percpu_timer = 0; | 353 | percpu_timer = 0; |
| 606 | apbt_num_timers_used = 1; | 354 | apbt_num_timers_used = 1; |
| 607 | adev = &per_cpu(cpu_apbt_dev, 0); | ||
| 608 | adev->flags &= ~APBT_DEV_USED; | ||
| 609 | } | 355 | } |
| 610 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); | 356 | pr_debug("%s: %d APB timers used\n", __func__, apbt_num_timers_used); |
| 611 | 357 | ||
| 612 | /* here we set up per CPU timer data structure */ | 358 | /* here we set up per CPU timer data structure */ |
| 613 | apbt_devs = kzalloc(sizeof(struct apbt_dev) * apbt_num_timers_used, | ||
| 614 | GFP_KERNEL); | ||
| 615 | if (!apbt_devs) { | ||
| 616 | printk(KERN_ERR "Failed to allocate APB timer devices\n"); | ||
| 617 | return; | ||
| 618 | } | ||
| 619 | for (i = 0; i < apbt_num_timers_used; i++) { | 359 | for (i = 0; i < apbt_num_timers_used; i++) { |
| 620 | adev = &per_cpu(cpu_apbt_dev, i); | 360 | adev = &per_cpu(cpu_apbt_dev, i); |
| 621 | adev->num = i; | 361 | adev->num = i; |
| 622 | adev->cpu = i; | 362 | adev->cpu = i; |
| 623 | p_mtmr = sfi_get_mtmr(i); | 363 | p_mtmr = sfi_get_mtmr(i); |
| 624 | if (p_mtmr) { | 364 | if (p_mtmr) |
| 625 | adev->tick = p_mtmr->freq_hz; | ||
| 626 | adev->irq = p_mtmr->irq; | 365 | adev->irq = p_mtmr->irq; |
| 627 | } else | 366 | else |
| 628 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); | 367 | printk(KERN_ERR "Failed to get timer for cpu %d\n", i); |
| 629 | adev->count = 0; | 368 | snprintf(adev->name, sizeof(adev->name) - 1, "apbt%d", i); |
| 630 | sprintf(adev->name, "apbt%d", i); | ||
| 631 | } | 369 | } |
| 632 | #endif | 370 | #endif |
| 633 | 371 | ||
| @@ -639,17 +377,8 @@ out_noapbt: | |||
| 639 | panic("failed to enable APB timer\n"); | 377 | panic("failed to enable APB timer\n"); |
| 640 | } | 378 | } |
| 641 | 379 | ||
| 642 | static inline void apbt_disable(int n) | ||
| 643 | { | ||
| 644 | if (is_apbt_capable()) { | ||
| 645 | unsigned long ctrl = apbt_readl(n, APBTMR_N_CONTROL); | ||
| 646 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 647 | apbt_writel(n, ctrl, APBTMR_N_CONTROL); | ||
| 648 | } | ||
| 649 | } | ||
| 650 | |||
| 651 | /* called before apb_timer_enable, use early map */ | 380 | /* called before apb_timer_enable, use early map */ |
| 652 | unsigned long apbt_quick_calibrate() | 381 | unsigned long apbt_quick_calibrate(void) |
| 653 | { | 382 | { |
| 654 | int i, scale; | 383 | int i, scale; |
| 655 | u64 old, new; | 384 | u64 old, new; |
| @@ -658,31 +387,31 @@ unsigned long apbt_quick_calibrate() | |||
| 658 | u32 loop, shift; | 387 | u32 loop, shift; |
| 659 | 388 | ||
| 660 | apbt_set_mapping(); | 389 | apbt_set_mapping(); |
| 661 | apbt_start_counter(phy_cs_timer_id); | 390 | dw_apb_clocksource_start(clocksource_apbt); |
| 662 | 391 | ||
| 663 | /* check if the timer can count down, otherwise return */ | 392 | /* check if the timer can count down, otherwise return */ |
| 664 | old = apbt_read_clocksource(&clocksource_apbt); | 393 | old = dw_apb_clocksource_read(clocksource_apbt); |
| 665 | i = 10000; | 394 | i = 10000; |
| 666 | while (--i) { | 395 | while (--i) { |
| 667 | if (old != apbt_read_clocksource(&clocksource_apbt)) | 396 | if (old != dw_apb_clocksource_read(clocksource_apbt)) |
| 668 | break; | 397 | break; |
| 669 | } | 398 | } |
| 670 | if (!i) | 399 | if (!i) |
| 671 | goto failed; | 400 | goto failed; |
| 672 | 401 | ||
| 673 | /* count 16 ms */ | 402 | /* count 16 ms */ |
| 674 | loop = (apbt_freq * 1000) << 4; | 403 | loop = (apbt_freq / 1000) << 4; |
| 675 | 404 | ||
| 676 | /* restart the timer to ensure it won't get to 0 in the calibration */ | 405 | /* restart the timer to ensure it won't get to 0 in the calibration */ |
| 677 | apbt_start_counter(phy_cs_timer_id); | 406 | dw_apb_clocksource_start(clocksource_apbt); |
| 678 | 407 | ||
| 679 | old = apbt_read_clocksource(&clocksource_apbt); | 408 | old = dw_apb_clocksource_read(clocksource_apbt); |
| 680 | old += loop; | 409 | old += loop; |
| 681 | 410 | ||
| 682 | t1 = __native_read_tsc(); | 411 | t1 = __native_read_tsc(); |
| 683 | 412 | ||
| 684 | do { | 413 | do { |
| 685 | new = apbt_read_clocksource(&clocksource_apbt); | 414 | new = dw_apb_clocksource_read(clocksource_apbt); |
| 686 | } while (new < old); | 415 | } while (new < old); |
| 687 | 416 | ||
| 688 | t2 = __native_read_tsc(); | 417 | t2 = __native_read_tsc(); |
| @@ -694,7 +423,7 @@ unsigned long apbt_quick_calibrate() | |||
| 694 | return 0; | 423 | return 0; |
| 695 | } | 424 | } |
| 696 | scale = (int)div_u64((t2 - t1), loop >> shift); | 425 | scale = (int)div_u64((t2 - t1), loop >> shift); |
| 697 | khz = (scale * apbt_freq * 1000) >> shift; | 426 | khz = (scale * (apbt_freq / 1000)) >> shift; |
| 698 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); | 427 | printk(KERN_INFO "TSC freq calculated by APB timer is %lu khz\n", khz); |
| 699 | return khz; | 428 | return khz; |
| 700 | failed: | 429 | failed: |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index d8d3e02b912c..34e9c4f88926 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
| @@ -12,3 +12,6 @@ config CLKBLD_I8253 | |||
| 12 | 12 | ||
| 13 | config CLKSRC_MMIO | 13 | config CLKSRC_MMIO |
| 14 | bool | 14 | bool |
| 15 | |||
| 16 | config DW_APB_TIMER | ||
| 17 | bool | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 7922a0cfc99f..85ad1646a7b7 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
| @@ -8,3 +8,4 @@ obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o | |||
| 8 | obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o | 8 | obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o |
| 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o | 9 | obj-$(CONFIG_CLKBLD_I8253) += i8253.o |
| 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o | 10 | obj-$(CONFIG_CLKSRC_MMIO) += mmio.o |
| 11 | obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o | ||
diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c new file mode 100644 index 000000000000..580f870541a3 --- /dev/null +++ b/drivers/clocksource/dw_apb_timer.c | |||
| @@ -0,0 +1,401 @@ | |||
| 1 | /* | ||
| 2 | * (C) Copyright 2009 Intel Corporation | ||
| 3 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
| 4 | * | ||
| 5 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * Support for the Synopsys DesignWare APB Timers. | ||
| 12 | */ | ||
| 13 | #include <linux/dw_apb_timer.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/irq.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | |||
| 21 | #define APBT_MIN_PERIOD 4 | ||
| 22 | #define APBT_MIN_DELTA_USEC 200 | ||
| 23 | |||
| 24 | #define APBTMR_N_LOAD_COUNT 0x00 | ||
| 25 | #define APBTMR_N_CURRENT_VALUE 0x04 | ||
| 26 | #define APBTMR_N_CONTROL 0x08 | ||
| 27 | #define APBTMR_N_EOI 0x0c | ||
| 28 | #define APBTMR_N_INT_STATUS 0x10 | ||
| 29 | |||
| 30 | #define APBTMRS_INT_STATUS 0xa0 | ||
| 31 | #define APBTMRS_EOI 0xa4 | ||
| 32 | #define APBTMRS_RAW_INT_STATUS 0xa8 | ||
| 33 | #define APBTMRS_COMP_VERSION 0xac | ||
| 34 | |||
| 35 | #define APBTMR_CONTROL_ENABLE (1 << 0) | ||
| 36 | /* 1: periodic, 0:free running. */ | ||
| 37 | #define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) | ||
| 38 | #define APBTMR_CONTROL_INT (1 << 2) | ||
| 39 | |||
| 40 | static inline struct dw_apb_clock_event_device * | ||
| 41 | ced_to_dw_apb_ced(struct clock_event_device *evt) | ||
| 42 | { | ||
| 43 | return container_of(evt, struct dw_apb_clock_event_device, ced); | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline struct dw_apb_clocksource * | ||
| 47 | clocksource_to_dw_apb_clocksource(struct clocksource *cs) | ||
| 48 | { | ||
| 49 | return container_of(cs, struct dw_apb_clocksource, cs); | ||
| 50 | } | ||
| 51 | |||
| 52 | static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs) | ||
| 53 | { | ||
| 54 | return readl(timer->base + offs); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void apbt_writel(struct dw_apb_timer *timer, unsigned long val, | ||
| 58 | unsigned long offs) | ||
| 59 | { | ||
| 60 | writel(val, timer->base + offs); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void apbt_disable_int(struct dw_apb_timer *timer) | ||
| 64 | { | ||
| 65 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); | ||
| 66 | |||
| 67 | ctrl |= APBTMR_CONTROL_INT; | ||
| 68 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); | ||
| 69 | } | ||
| 70 | |||
| 71 | /** | ||
| 72 | * dw_apb_clockevent_pause() - stop the clock_event_device from running | ||
| 73 | * | ||
| 74 | * @dw_ced: The APB clock to stop generating events. | ||
| 75 | */ | ||
| 76 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) | ||
| 77 | { | ||
| 78 | disable_irq(dw_ced->timer.irq); | ||
| 79 | apbt_disable_int(&dw_ced->timer); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void apbt_eoi(struct dw_apb_timer *timer) | ||
| 83 | { | ||
| 84 | apbt_readl(timer, APBTMR_N_EOI); | ||
| 85 | } | ||
| 86 | |||
| 87 | static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) | ||
| 88 | { | ||
| 89 | struct clock_event_device *evt = data; | ||
| 90 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
| 91 | |||
| 92 | if (!evt->event_handler) { | ||
| 93 | pr_info("Spurious APBT timer interrupt %d", irq); | ||
| 94 | return IRQ_NONE; | ||
| 95 | } | ||
| 96 | |||
| 97 | if (dw_ced->eoi) | ||
| 98 | dw_ced->eoi(&dw_ced->timer); | ||
| 99 | |||
| 100 | evt->event_handler(evt); | ||
| 101 | return IRQ_HANDLED; | ||
| 102 | } | ||
| 103 | |||
| 104 | static void apbt_enable_int(struct dw_apb_timer *timer) | ||
| 105 | { | ||
| 106 | unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL); | ||
| 107 | /* clear pending intr */ | ||
| 108 | apbt_readl(timer, APBTMR_N_EOI); | ||
| 109 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 110 | apbt_writel(timer, ctrl, APBTMR_N_CONTROL); | ||
| 111 | } | ||
| 112 | |||
| 113 | static void apbt_set_mode(enum clock_event_mode mode, | ||
| 114 | struct clock_event_device *evt) | ||
| 115 | { | ||
| 116 | unsigned long ctrl; | ||
| 117 | unsigned long period; | ||
| 118 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
| 119 | |||
| 120 | pr_debug("%s CPU %d mode=%d\n", __func__, first_cpu(*evt->cpumask), | ||
| 121 | mode); | ||
| 122 | |||
| 123 | switch (mode) { | ||
| 124 | case CLOCK_EVT_MODE_PERIODIC: | ||
| 125 | period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); | ||
| 126 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
| 127 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; | ||
| 128 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 129 | /* | ||
| 130 | * DW APB p. 46, have to disable timer before load counter, | ||
| 131 | * may cause sync problem. | ||
| 132 | */ | ||
| 133 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 134 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 135 | udelay(1); | ||
| 136 | pr_debug("Setting clock period %lu for HZ %d\n", period, HZ); | ||
| 137 | apbt_writel(&dw_ced->timer, period, APBTMR_N_LOAD_COUNT); | ||
| 138 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 139 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 140 | break; | ||
| 141 | |||
| 142 | case CLOCK_EVT_MODE_ONESHOT: | ||
| 143 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
| 144 | /* | ||
| 145 | * set free running mode, this mode will let timer reload max | ||
| 146 | * timeout which will give time (3min on 25MHz clock) to rearm | ||
| 147 | * the next event, therefore emulate the one-shot mode. | ||
| 148 | */ | ||
| 149 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 150 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 151 | |||
| 152 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 153 | /* write again to set free running mode */ | ||
| 154 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 155 | |||
| 156 | /* | ||
| 157 | * DW APB p. 46, load counter with all 1s before starting free | ||
| 158 | * running mode. | ||
| 159 | */ | ||
| 160 | apbt_writel(&dw_ced->timer, ~0, APBTMR_N_LOAD_COUNT); | ||
| 161 | ctrl &= ~APBTMR_CONTROL_INT; | ||
| 162 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 163 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 164 | break; | ||
| 165 | |||
| 166 | case CLOCK_EVT_MODE_UNUSED: | ||
| 167 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
| 168 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
| 169 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 170 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 171 | break; | ||
| 172 | |||
| 173 | case CLOCK_EVT_MODE_RESUME: | ||
| 174 | apbt_enable_int(&dw_ced->timer); | ||
| 175 | break; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | static int apbt_next_event(unsigned long delta, | ||
| 180 | struct clock_event_device *evt) | ||
| 181 | { | ||
| 182 | unsigned long ctrl; | ||
| 183 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); | ||
| 184 | |||
| 185 | /* Disable timer */ | ||
| 186 | ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL); | ||
| 187 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 188 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 189 | /* write new count */ | ||
| 190 | apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT); | ||
| 191 | ctrl |= APBTMR_CONTROL_ENABLE; | ||
| 192 | apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL); | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * dw_apb_clockevent_init() - use an APB timer as a clock_event_device | ||
| 199 | * | ||
| 200 | * @cpu: The CPU the events will be targeted at. | ||
| 201 | * @name: The name used for the timer and the IRQ for it. | ||
| 202 | * @rating: The rating to give the timer. | ||
| 203 | * @base: I/O base for the timer registers. | ||
| 204 | * @irq: The interrupt number to use for the timer. | ||
| 205 | * @freq: The frequency that the timer counts at. | ||
| 206 | * | ||
| 207 | * This creates a clock_event_device for using with the generic clock layer | ||
| 208 | * but does not start and register it. This should be done with | ||
| 209 | * dw_apb_clockevent_register() as the next step. If this is the first time | ||
| 210 | * it has been called for a timer then the IRQ will be requested, if not it | ||
| 211 | * just be enabled to allow CPU hotplug to avoid repeatedly requesting and | ||
| 212 | * releasing the IRQ. | ||
| 213 | */ | ||
| 214 | struct dw_apb_clock_event_device * | ||
| 215 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, | ||
| 216 | void __iomem *base, int irq, unsigned long freq) | ||
| 217 | { | ||
| 218 | struct dw_apb_clock_event_device *dw_ced = | ||
| 219 | kzalloc(sizeof(*dw_ced), GFP_KERNEL); | ||
| 220 | int err; | ||
| 221 | |||
| 222 | if (!dw_ced) | ||
| 223 | return NULL; | ||
| 224 | |||
| 225 | dw_ced->timer.base = base; | ||
| 226 | dw_ced->timer.irq = irq; | ||
| 227 | dw_ced->timer.freq = freq; | ||
| 228 | |||
| 229 | clockevents_calc_mult_shift(&dw_ced->ced, freq, APBT_MIN_PERIOD); | ||
| 230 | dw_ced->ced.max_delta_ns = clockevent_delta2ns(0x7fffffff, | ||
| 231 | &dw_ced->ced); | ||
| 232 | dw_ced->ced.min_delta_ns = clockevent_delta2ns(5000, &dw_ced->ced); | ||
| 233 | dw_ced->ced.cpumask = cpumask_of(cpu); | ||
| 234 | dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
| 235 | dw_ced->ced.set_mode = apbt_set_mode; | ||
| 236 | dw_ced->ced.set_next_event = apbt_next_event; | ||
| 237 | dw_ced->ced.irq = dw_ced->timer.irq; | ||
| 238 | dw_ced->ced.rating = rating; | ||
| 239 | dw_ced->ced.name = name; | ||
| 240 | |||
| 241 | dw_ced->irqaction.name = dw_ced->ced.name; | ||
| 242 | dw_ced->irqaction.handler = dw_apb_clockevent_irq; | ||
| 243 | dw_ced->irqaction.dev_id = &dw_ced->ced; | ||
| 244 | dw_ced->irqaction.irq = irq; | ||
| 245 | dw_ced->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | | ||
| 246 | IRQF_NOBALANCING | | ||
| 247 | IRQF_DISABLED; | ||
| 248 | |||
| 249 | dw_ced->eoi = apbt_eoi; | ||
| 250 | err = setup_irq(irq, &dw_ced->irqaction); | ||
| 251 | if (err) { | ||
| 252 | pr_err("failed to request timer irq\n"); | ||
| 253 | kfree(dw_ced); | ||
| 254 | dw_ced = NULL; | ||
| 255 | } | ||
| 256 | |||
| 257 | return dw_ced; | ||
| 258 | } | ||
| 259 | |||
| 260 | /** | ||
| 261 | * dw_apb_clockevent_resume() - resume a clock that has been paused. | ||
| 262 | * | ||
| 263 | * @dw_ced: The APB clock to resume. | ||
| 264 | */ | ||
| 265 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) | ||
| 266 | { | ||
| 267 | enable_irq(dw_ced->timer.irq); | ||
| 268 | } | ||
| 269 | |||
| 270 | /** | ||
| 271 | * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. | ||
| 272 | * | ||
| 273 | * @dw_ced: The APB clock to stop generating the events. | ||
| 274 | */ | ||
| 275 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) | ||
| 276 | { | ||
| 277 | free_irq(dw_ced->timer.irq, &dw_ced->ced); | ||
| 278 | } | ||
| 279 | |||
| 280 | /** | ||
| 281 | * dw_apb_clockevent_register() - register the clock with the generic layer | ||
| 282 | * | ||
| 283 | * @dw_ced: The APB clock to register as a clock_event_device. | ||
| 284 | */ | ||
| 285 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) | ||
| 286 | { | ||
| 287 | apbt_writel(&dw_ced->timer, 0, APBTMR_N_CONTROL); | ||
| 288 | clockevents_register_device(&dw_ced->ced); | ||
| 289 | apbt_enable_int(&dw_ced->timer); | ||
| 290 | } | ||
| 291 | |||
| 292 | /** | ||
| 293 | * dw_apb_clocksource_start() - start the clocksource counting. | ||
| 294 | * | ||
| 295 | * @dw_cs: The clocksource to start. | ||
| 296 | * | ||
| 297 | * This is used to start the clocksource before registration and can be used | ||
| 298 | * to enable calibration of timers. | ||
| 299 | */ | ||
| 300 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) | ||
| 301 | { | ||
| 302 | /* | ||
| 303 | * start count down from 0xffff_ffff. this is done by toggling the | ||
| 304 | * enable bit then load initial load count to ~0. | ||
| 305 | */ | ||
| 306 | unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL); | ||
| 307 | |||
| 308 | ctrl &= ~APBTMR_CONTROL_ENABLE; | ||
| 309 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); | ||
| 310 | apbt_writel(&dw_cs->timer, ~0, APBTMR_N_LOAD_COUNT); | ||
| 311 | /* enable, mask interrupt */ | ||
| 312 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; | ||
| 313 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); | ||
| 314 | apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL); | ||
| 315 | /* read it once to get cached counter value initialized */ | ||
| 316 | dw_apb_clocksource_read(dw_cs); | ||
| 317 | } | ||
| 318 | |||
| 319 | static cycle_t __apbt_read_clocksource(struct clocksource *cs) | ||
| 320 | { | ||
| 321 | unsigned long current_count; | ||
| 322 | struct dw_apb_clocksource *dw_cs = | ||
| 323 | clocksource_to_dw_apb_clocksource(cs); | ||
| 324 | |||
| 325 | current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); | ||
| 326 | |||
| 327 | return (cycle_t)~current_count; | ||
| 328 | } | ||
| 329 | |||
| 330 | static void apbt_restart_clocksource(struct clocksource *cs) | ||
| 331 | { | ||
| 332 | struct dw_apb_clocksource *dw_cs = | ||
| 333 | clocksource_to_dw_apb_clocksource(cs); | ||
| 334 | |||
| 335 | dw_apb_clocksource_start(dw_cs); | ||
| 336 | } | ||
| 337 | |||
| 338 | /** | ||
| 339 | * dw_apb_clocksource_init() - use an APB timer as a clocksource. | ||
| 340 | * | ||
| 341 | * @rating: The rating to give the clocksource. | ||
| 342 | * @name: The name for the clocksource. | ||
| 343 | * @base: The I/O base for the timer registers. | ||
| 344 | * @freq: The frequency that the timer counts at. | ||
| 345 | * | ||
| 346 | * This creates a clocksource using an APB timer but does not yet register it | ||
| 347 | * with the clocksource system. This should be done with | ||
| 348 | * dw_apb_clocksource_register() as the next step. | ||
| 349 | */ | ||
| 350 | struct dw_apb_clocksource * | ||
| 351 | dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, | ||
| 352 | unsigned long freq) | ||
| 353 | { | ||
| 354 | struct dw_apb_clocksource *dw_cs = kzalloc(sizeof(*dw_cs), GFP_KERNEL); | ||
| 355 | |||
| 356 | if (!dw_cs) | ||
| 357 | return NULL; | ||
| 358 | |||
| 359 | dw_cs->timer.base = base; | ||
| 360 | dw_cs->timer.freq = freq; | ||
| 361 | dw_cs->cs.name = name; | ||
| 362 | dw_cs->cs.rating = rating; | ||
| 363 | dw_cs->cs.read = __apbt_read_clocksource; | ||
| 364 | dw_cs->cs.mask = CLOCKSOURCE_MASK(32); | ||
| 365 | dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; | ||
| 366 | dw_cs->cs.resume = apbt_restart_clocksource; | ||
| 367 | |||
| 368 | return dw_cs; | ||
| 369 | } | ||
| 370 | |||
| 371 | /** | ||
| 372 | * dw_apb_clocksource_register() - register the APB clocksource. | ||
| 373 | * | ||
| 374 | * @dw_cs: The clocksource to register. | ||
| 375 | */ | ||
| 376 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) | ||
| 377 | { | ||
| 378 | clocksource_register_hz(&dw_cs->cs, dw_cs->timer.freq); | ||
| 379 | } | ||
| 380 | |||
| 381 | /** | ||
| 382 | * dw_apb_clocksource_read() - read the current value of a clocksource. | ||
| 383 | * | ||
| 384 | * @dw_cs: The clocksource to read. | ||
| 385 | */ | ||
| 386 | cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) | ||
| 387 | { | ||
| 388 | return (cycle_t)~apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE); | ||
| 389 | } | ||
| 390 | |||
| 391 | /** | ||
| 392 | * dw_apb_clocksource_unregister() - unregister and free a clocksource. | ||
| 393 | * | ||
| 394 | * @dw_cs: The clocksource to unregister/free. | ||
| 395 | */ | ||
| 396 | void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs) | ||
| 397 | { | ||
| 398 | clocksource_unregister(&dw_cs->cs); | ||
| 399 | |||
| 400 | kfree(dw_cs); | ||
| 401 | } | ||
diff --git a/include/linux/dw_apb_timer.h b/include/linux/dw_apb_timer.h new file mode 100644 index 000000000000..49638ea3b776 --- /dev/null +++ b/include/linux/dw_apb_timer.h | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | * (C) Copyright 2009 Intel Corporation | ||
| 3 | * Author: Jacob Pan (jacob.jun.pan@intel.com) | ||
| 4 | * | ||
| 5 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * Support for the Synopsys DesignWare APB Timers. | ||
| 12 | */ | ||
| 13 | #ifndef __DW_APB_TIMER_H__ | ||
| 14 | #define __DW_APB_TIMER_H__ | ||
| 15 | |||
| 16 | #include <linux/clockchips.h> | ||
| 17 | #include <linux/clocksource.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | |||
| 20 | #define APBTMRS_REG_SIZE 0x14 | ||
| 21 | |||
| 22 | struct dw_apb_timer { | ||
| 23 | void __iomem *base; | ||
| 24 | unsigned long freq; | ||
| 25 | int irq; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct dw_apb_clock_event_device { | ||
| 29 | struct clock_event_device ced; | ||
| 30 | struct dw_apb_timer timer; | ||
| 31 | struct irqaction irqaction; | ||
| 32 | void (*eoi)(struct dw_apb_timer *); | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct dw_apb_clocksource { | ||
| 36 | struct dw_apb_timer timer; | ||
| 37 | struct clocksource cs; | ||
| 38 | }; | ||
| 39 | |||
| 40 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced); | ||
| 41 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced); | ||
| 42 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced); | ||
| 43 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced); | ||
| 44 | |||
| 45 | struct dw_apb_clock_event_device * | ||
| 46 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, | ||
| 47 | void __iomem *base, int irq, unsigned long freq); | ||
| 48 | struct dw_apb_clocksource * | ||
| 49 | dw_apb_clocksource_init(unsigned rating, char *name, void __iomem *base, | ||
| 50 | unsigned long freq); | ||
| 51 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs); | ||
| 52 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs); | ||
| 53 | cycle_t dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs); | ||
| 54 | void dw_apb_clocksource_unregister(struct dw_apb_clocksource *dw_cs); | ||
| 55 | |||
| 56 | #endif /* __DW_APB_TIMER_H__ */ | ||
