Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'timers-v5.9' of https://git.linaro.org/people/daniel.lezcano/linux into timers/core

Pull clock event/surce driver changes from Daniel Lezcano:

- Add sama5d2 support and rework the 32kHz clock handling (Alexandre Belloni)
- Add the high resolution support for SMP/SMT on the Ingenic timer (Zhou Yanjie)
- Add support for i.MX TPM driver with ARM64 (Anson Huang)
- Fix typo by replacing KHz to kHz (Geert Uytterhoeven)
- Add 32kHz support by setting the minimum ticks to 5 on Nomadik MTU (Linus Walleij)
- Replace HTTP links with HTTPS ones for security reasons (Alexander A. Klimov)
- Add support for the Ingenic X1000 OST (Zhou Yanjie)

+991 -173
-56
Documentation/devicetree/bindings/mfd/atmel-tcb.txt
··· 1 - * Device tree bindings for Atmel Timer Counter Blocks 2 - - compatible: Should be "atmel,<chip>-tcb", "simple-mfd", "syscon". 3 - <chip> can be "at91rm9200" or "at91sam9x5" 4 - - reg: Should contain registers location and length 5 - - #address-cells: has to be 1 6 - - #size-cells: has to be 0 7 - - interrupts: Should contain all interrupts for the TC block 8 - Note that you can specify several interrupt cells if the TC 9 - block has one interrupt per channel. 10 - - clock-names: tuple listing input clock names. 11 - Required elements: "t0_clk", "slow_clk" 12 - Optional elements: "t1_clk", "t2_clk" 13 - - clocks: phandles to input clocks. 14 - 15 - The TCB can expose multiple subdevices: 16 - * a timer 17 - - compatible: Should be "atmel,tcb-timer" 18 - - reg: Should contain the TCB channels to be used. If the 19 - counter width is 16 bits (at91rm9200-tcb), two consecutive 20 - channels are needed. Else, only one channel will be used. 21 - 22 - Examples: 23 - 24 - One interrupt per TC block: 25 - tcb0: timer@fff7c000 { 26 - compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; 27 - #address-cells = <1>; 28 - #size-cells = <0>; 29 - reg = <0xfff7c000 0x100>; 30 - interrupts = <18 4>; 31 - clocks = <&tcb0_clk>, <&clk32k>; 32 - clock-names = "t0_clk", "slow_clk"; 33 - 34 - timer@0 { 35 - compatible = "atmel,tcb-timer"; 36 - reg = <0>, <1>; 37 - }; 38 - 39 - timer@2 { 40 - compatible = "atmel,tcb-timer"; 41 - reg = <2>; 42 - }; 43 - }; 44 - 45 - One interrupt per TC channel in a TC block: 46 - tcb1: timer@fffdc000 { 47 - compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; 48 - #address-cells = <1>; 49 - #size-cells = <0>; 50 - reg = <0xfffdc000 0x100>; 51 - interrupts = <26 4>, <27 4>, <28 4>; 52 - clocks = <&tcb1_clk>, <&clk32k>; 53 - clock-names = "t0_clk", "slow_clk"; 54 - }; 55 - 56 -
+155
Documentation/devicetree/bindings/soc/microchip/atmel,at91rm9200-tcb.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: "http://devicetree.org/schemas/soc/microchip/atmel,at91rm9200-tcb.yaml#" 5 + $schema: "http://devicetree.org/meta-schemas/core.yaml#" 6 + 7 + title: Atmel Timer Counter Block 8 + 9 + maintainers: 10 + - Alexandre Belloni <alexandre.belloni@bootlin.com> 11 + 12 + description: | 13 + The Atmel (now Microchip) SoCs have timers named Timer Counter Block. Each 14 + timer has three channels with two counters each. 15 + 16 + properties: 17 + compatible: 18 + items: 19 + - enum: 20 + - atmel,at91rm9200-tcb 21 + - atmel,at91sam9x5-tcb 22 + - atmel,sama5d2-tcb 23 + - const: simple-mfd 24 + - const: syscon 25 + 26 + reg: 27 + maxItems: 1 28 + 29 + interrupts: 30 + description: 31 + List of interrupts. One interrupt per TCB channel if available or one 32 + interrupt for the TC block 33 + minItems: 1 34 + maxItems: 3 35 + 36 + clock-names: 37 + description: 38 + List of clock names. Always includes t0_clk and slow clk. Also includes 39 + t1_clk and t2_clk if a clock per channel is available. 40 + minItems: 2 41 + maxItems: 4 42 + 43 + clocks: 44 + minItems: 2 45 + maxItems: 4 46 + 47 + '#address-cells': 48 + const: 1 49 + 50 + '#size-cells': 51 + const: 0 52 + 53 + patternProperties: 54 + "^timer@[0-2]$": 55 + description: The timer block channels that are used as timers. 56 + type: object 57 + properties: 58 + compatible: 59 + const: atmel,tcb-timer 60 + reg: 61 + description: 62 + List of channels to use for this particular timer. 63 + minItems: 1 64 + maxItems: 3 65 + 66 + required: 67 + - compatible 68 + - reg 69 + 70 + allOf: 71 + - if: 72 + properties: 73 + compatible: 74 + contains: 75 + const: atmel,sama5d2-tcb 76 + then: 77 + properties: 78 + clocks: 79 + minItems: 3 80 + maxItems: 3 81 + clock-names: 82 + items: 83 + - const: t0_clk 84 + - const: gclk 85 + - const: slow_clk 86 + else: 87 + properties: 88 + clocks: 89 + minItems: 2 90 + maxItems: 4 91 + clock-names: 92 + oneOf: 93 + - items: 94 + - const: t0_clk 95 + - const: slow_clk 96 + - items: 97 + - const: t0_clk 98 + - const: t1_clk 99 + - const: t2_clk 100 + - const: slow_clk 101 + 102 + required: 103 + - compatible 104 + - reg 105 + - interrupts 106 + - clocks 107 + - clock-names 108 + - '#address-cells' 109 + - '#size-cells' 110 + 111 + additionalProperties: false 112 + 113 + examples: 114 + - | 115 + /* One interrupt per TC block: */ 116 + tcb0: timer@fff7c000 { 117 + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; 118 + #address-cells = <1>; 119 + #size-cells = <0>; 120 + reg = <0xfff7c000 0x100>; 121 + interrupts = <18 4>; 122 + clocks = <&tcb0_clk>, <&clk32k>; 123 + clock-names = "t0_clk", "slow_clk"; 124 + 125 + timer@0 { 126 + compatible = "atmel,tcb-timer"; 127 + reg = <0>, <1>; 128 + }; 129 + 130 + timer@2 { 131 + compatible = "atmel,tcb-timer"; 132 + reg = <2>; 133 + }; 134 + }; 135 + 136 + /* One interrupt per TC channel in a TC block: */ 137 + tcb1: timer@fffdc000 { 138 + compatible = "atmel,at91rm9200-tcb", "simple-mfd", "syscon"; 139 + #address-cells = <1>; 140 + #size-cells = <0>; 141 + reg = <0xfffdc000 0x100>; 142 + interrupts = <26 4>, <27 4>, <28 4>; 143 + clocks = <&tcb1_clk>, <&clk32k>; 144 + clock-names = "t0_clk", "slow_clk"; 145 + 146 + timer@0 { 147 + compatible = "atmel,tcb-timer"; 148 + reg = <0>; 149 + }; 150 + 151 + timer@1 { 152 + compatible = "atmel,tcb-timer"; 153 + reg = <1>; 154 + }; 155 + };
+63
Documentation/devicetree/bindings/timer/ingenic,sysost.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/timer/ingenic,sysost.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Bindings for SYSOST in Ingenic XBurst family SoCs 8 + 9 + maintainers: 10 + - 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> 11 + 12 + description: 13 + The SYSOST in an Ingenic SoC provides one 64bit timer for clocksource 14 + and one or more 32bit timers for clockevent. 15 + 16 + properties: 17 + "#clock-cells": 18 + const: 1 19 + 20 + compatible: 21 + enum: 22 + - ingenic,x1000-ost 23 + - ingenic,x2000-ost 24 + 25 + reg: 26 + maxItems: 1 27 + 28 + clocks: 29 + maxItems: 1 30 + 31 + clock-names: 32 + const: ost 33 + 34 + interrupts: 35 + maxItems: 1 36 + 37 + required: 38 + - "#clock-cells" 39 + - compatible 40 + - reg 41 + - clocks 42 + - clock-names 43 + - interrupts 44 + 45 + additionalProperties: false 46 + 47 + examples: 48 + - | 49 + #include <dt-bindings/clock/x1000-cgu.h> 50 + 51 + ost: timer@12000000 { 52 + compatible = "ingenic,x1000-ost"; 53 + reg = <0x12000000 0x3c>; 54 + 55 + #clock-cells = <1>; 56 + 57 + clocks = <&cgu X1000_CLK_OST>; 58 + clock-names = "ost"; 59 + 60 + interrupt-parent = <&cpuintc>; 61 + interrupts = <3>; 62 + }; 63 + ...
+1 -1
Documentation/devicetree/bindings/timer/ti,keystone-timer.txt
··· 10 10 when the counter reaches preset counter values. 11 11 12 12 Documentation: 13 - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf 13 + https://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf 14 14 15 15 Required properties: 16 16
+6 -6
arch/arm/boot/dts/sama5d2.dtsi
··· 375 375 }; 376 376 377 377 tcb0: timer@f800c000 { 378 - compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; 378 + compatible = "atmel,sama5d2-tcb", "simple-mfd", "syscon"; 379 379 #address-cells = <1>; 380 380 #size-cells = <0>; 381 381 reg = <0xf800c000 0x100>; 382 382 interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>; 383 - clocks = <&pmc PMC_TYPE_PERIPHERAL 35>, <&clk32k>; 384 - clock-names = "t0_clk", "slow_clk"; 383 + clocks = <&pmc PMC_TYPE_PERIPHERAL 35>, <&pmc PMC_TYPE_GCK 35>, <&clk32k>; 384 + clock-names = "t0_clk", "gclk", "slow_clk"; 385 385 }; 386 386 387 387 tcb1: timer@f8010000 { 388 - compatible = "atmel,at91sam9x5-tcb", "simple-mfd", "syscon"; 388 + compatible = "atmel,sama5d2-tcb", "simple-mfd", "syscon"; 389 389 #address-cells = <1>; 390 390 #size-cells = <0>; 391 391 reg = <0xf8010000 0x100>; 392 392 interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; 393 - clocks = <&pmc PMC_TYPE_PERIPHERAL 36>, <&clk32k>; 394 - clock-names = "t0_clk", "slow_clk"; 393 + clocks = <&pmc PMC_TYPE_PERIPHERAL 36>, <&pmc PMC_TYPE_GCK 36>, <&clk32k>; 394 + clock-names = "t0_clk", "gclk", "slow_clk"; 395 395 }; 396 396 397 397 hsmc: hsmc@f8014000 {
+13 -2
drivers/clocksource/Kconfig
··· 616 616 617 617 config CLKSRC_IMX_TPM 618 618 bool "Clocksource using i.MX TPM" if COMPILE_TEST 619 - depends on ARM && CLKDEV_LOOKUP 619 + depends on (ARM || ARM64) && CLKDEV_LOOKUP 620 620 select CLKSRC_MMIO 621 + select TIMER_OF 621 622 help 622 623 Enable this option to use IMX Timer/PWM Module (TPM) timer as 623 624 clocksource. ··· 697 696 help 698 697 Support for the timer/counter unit of the Ingenic JZ SoCs. 699 698 699 + config INGENIC_SYSOST 700 + bool "Clocksource/timer using the SYSOST in Ingenic X SoCs" 701 + depends on MIPS || COMPILE_TEST 702 + depends on COMMON_CLK 703 + select MFD_SYSCON 704 + select TIMER_OF 705 + select IRQ_DOMAIN 706 + help 707 + Support for the SYSOST of the Ingenic X Series SoCs. 708 + 700 709 config INGENIC_OST 701 - bool "Clocksource for Ingenic OS Timer" 710 + bool "Clocksource using the OST in Ingenic JZ SoCs" 702 711 depends on MIPS || COMPILE_TEST 703 712 depends on COMMON_CLK 704 713 select MFD_SYSCON
+1
drivers/clocksource/Makefile
··· 82 82 obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o 83 83 obj-$(CONFIG_H8300_TPU) += h8300_tpu.o 84 84 obj-$(CONFIG_INGENIC_OST) += ingenic-ost.o 85 + obj-$(CONFIG_INGENIC_SYSOST) += ingenic-sysost.o 85 86 obj-$(CONFIG_INGENIC_TIMER) += ingenic-timer.o 86 87 obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o 87 88 obj-$(CONFIG_X86_NUMACHIP) += numachip.o
+539
drivers/clocksource/ingenic-sysost.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Ingenic XBurst SoCs SYSOST clocks driver 4 + * Copyright (c) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> 5 + */ 6 + 7 + #include <linux/bitops.h> 8 + #include <linux/clk.h> 9 + #include <linux/clk-provider.h> 10 + #include <linux/clockchips.h> 11 + #include <linux/clocksource.h> 12 + #include <linux/interrupt.h> 13 + #include <linux/mfd/syscon.h> 14 + #include <linux/of_address.h> 15 + #include <linux/of_irq.h> 16 + #include <linux/sched_clock.h> 17 + #include <linux/slab.h> 18 + #include <linux/syscore_ops.h> 19 + 20 + #include <dt-bindings/clock/ingenic,sysost.h> 21 + 22 + /* OST register offsets */ 23 + #define OST_REG_OSTCCR 0x00 24 + #define OST_REG_OSTCR 0x08 25 + #define OST_REG_OSTFR 0x0c 26 + #define OST_REG_OSTMR 0x10 27 + #define OST_REG_OST1DFR 0x14 28 + #define OST_REG_OST1CNT 0x18 29 + #define OST_REG_OST2CNTL 0x20 30 + #define OST_REG_OSTCNT2HBUF 0x24 31 + #define OST_REG_OSTESR 0x34 32 + #define OST_REG_OSTECR 0x38 33 + 34 + /* bits within the OSTCCR register */ 35 + #define OSTCCR_PRESCALE1_MASK 0x3 36 + #define OSTCCR_PRESCALE2_MASK 0xc 37 + #define OSTCCR_PRESCALE1_LSB 0 38 + #define OSTCCR_PRESCALE2_LSB 2 39 + 40 + /* bits within the OSTCR register */ 41 + #define OSTCR_OST1CLR BIT(0) 42 + #define OSTCR_OST2CLR BIT(1) 43 + 44 + /* bits within the OSTFR register */ 45 + #define OSTFR_FFLAG BIT(0) 46 + 47 + /* bits within the OSTMR register */ 48 + #define OSTMR_FMASK BIT(0) 49 + 50 + /* bits within the OSTESR register */ 51 + #define OSTESR_OST1ENS BIT(0) 52 + #define OSTESR_OST2ENS BIT(1) 53 + 54 + /* bits within the OSTECR register */ 55 + #define OSTECR_OST1ENC BIT(0) 56 + #define OSTECR_OST2ENC BIT(1) 57 + 58 + struct ingenic_soc_info { 59 + unsigned int num_channels; 60 + }; 61 + 62 + struct ingenic_ost_clk_info { 63 + struct clk_init_data init_data; 64 + u8 ostccr_reg; 65 + }; 66 + 67 + struct ingenic_ost_clk { 68 + struct clk_hw hw; 69 + unsigned int idx; 70 + struct ingenic_ost *ost; 71 + const struct ingenic_ost_clk_info *info; 72 + }; 73 + 74 + struct ingenic_ost { 75 + void __iomem *base; 76 + const struct ingenic_soc_info *soc_info; 77 + struct clk *clk, *percpu_timer_clk, *global_timer_clk; 78 + struct clock_event_device cevt; 79 + struct clocksource cs; 80 + char name[20]; 81 + 82 + struct clk_hw_onecell_data *clocks; 83 + }; 84 + 85 + static struct ingenic_ost *ingenic_ost; 86 + 87 + static inline struct ingenic_ost_clk *to_ost_clk(struct clk_hw *hw) 88 + { 89 + return container_of(hw, struct ingenic_ost_clk, hw); 90 + } 91 + 92 + static unsigned long ingenic_ost_percpu_timer_recalc_rate(struct clk_hw *hw, 93 + unsigned long parent_rate) 94 + { 95 + struct ingenic_ost_clk *ost_clk = to_ost_clk(hw); 96 + const struct ingenic_ost_clk_info *info = ost_clk->info; 97 + unsigned int prescale; 98 + 99 + prescale = readl(ost_clk->ost->base + info->ostccr_reg); 100 + 101 + prescale = (prescale & OSTCCR_PRESCALE1_MASK) >> OSTCCR_PRESCALE1_LSB; 102 + 103 + return parent_rate >> (prescale * 2); 104 + } 105 + 106 + static unsigned long ingenic_ost_global_timer_recalc_rate(struct clk_hw *hw, 107 + unsigned long parent_rate) 108 + { 109 + struct ingenic_ost_clk *ost_clk = to_ost_clk(hw); 110 + const struct ingenic_ost_clk_info *info = ost_clk->info; 111 + unsigned int prescale; 112 + 113 + prescale = readl(ost_clk->ost->base + info->ostccr_reg); 114 + 115 + prescale = (prescale & OSTCCR_PRESCALE2_MASK) >> OSTCCR_PRESCALE2_LSB; 116 + 117 + return parent_rate >> (prescale * 2); 118 + } 119 + 120 + static u8 ingenic_ost_get_prescale(unsigned long rate, unsigned long req_rate) 121 + { 122 + u8 prescale; 123 + 124 + for (prescale = 0; prescale < 2; prescale++) 125 + if ((rate >> (prescale * 2)) <= req_rate) 126 + return prescale; 127 + 128 + return 2; /* /16 divider */ 129 + } 130 + 131 + static long ingenic_ost_round_rate(struct clk_hw *hw, unsigned long req_rate, 132 + unsigned long *parent_rate) 133 + { 134 + unsigned long rate = *parent_rate; 135 + u8 prescale; 136 + 137 + if (req_rate > rate) 138 + return rate; 139 + 140 + prescale = ingenic_ost_get_prescale(rate, req_rate); 141 + 142 + return rate >> (prescale * 2); 143 + } 144 + 145 + static int ingenic_ost_percpu_timer_set_rate(struct clk_hw *hw, unsigned long req_rate, 146 + unsigned long parent_rate) 147 + { 148 + struct ingenic_ost_clk *ost_clk = to_ost_clk(hw); 149 + const struct ingenic_ost_clk_info *info = ost_clk->info; 150 + u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate); 151 + int val; 152 + 153 + val = readl(ost_clk->ost->base + info->ostccr_reg); 154 + val = (val & ~OSTCCR_PRESCALE1_MASK) | (prescale << OSTCCR_PRESCALE1_LSB); 155 + writel(val, ost_clk->ost->base + info->ostccr_reg); 156 + 157 + return 0; 158 + } 159 + 160 + static int ingenic_ost_global_timer_set_rate(struct clk_hw *hw, unsigned long req_rate, 161 + unsigned long parent_rate) 162 + { 163 + struct ingenic_ost_clk *ost_clk = to_ost_clk(hw); 164 + const struct ingenic_ost_clk_info *info = ost_clk->info; 165 + u8 prescale = ingenic_ost_get_prescale(parent_rate, req_rate); 166 + int val; 167 + 168 + val = readl(ost_clk->ost->base + info->ostccr_reg); 169 + val = (val & ~OSTCCR_PRESCALE2_MASK) | (prescale << OSTCCR_PRESCALE2_LSB); 170 + writel(val, ost_clk->ost->base + info->ostccr_reg); 171 + 172 + return 0; 173 + } 174 + 175 + static const struct clk_ops ingenic_ost_percpu_timer_ops = { 176 + .recalc_rate = ingenic_ost_percpu_timer_recalc_rate, 177 + .round_rate = ingenic_ost_round_rate, 178 + .set_rate = ingenic_ost_percpu_timer_set_rate, 179 + }; 180 + 181 + static const struct clk_ops ingenic_ost_global_timer_ops = { 182 + .recalc_rate = ingenic_ost_global_timer_recalc_rate, 183 + .round_rate = ingenic_ost_round_rate, 184 + .set_rate = ingenic_ost_global_timer_set_rate, 185 + }; 186 + 187 + static const char * const ingenic_ost_clk_parents[] = { "ext" }; 188 + 189 + static const struct ingenic_ost_clk_info ingenic_ost_clk_info[] = { 190 + [OST_CLK_PERCPU_TIMER] = { 191 + .init_data = { 192 + .name = "percpu timer", 193 + .parent_names = ingenic_ost_clk_parents, 194 + .num_parents = ARRAY_SIZE(ingenic_ost_clk_parents), 195 + .ops = &ingenic_ost_percpu_timer_ops, 196 + .flags = CLK_SET_RATE_UNGATE, 197 + }, 198 + .ostccr_reg = OST_REG_OSTCCR, 199 + }, 200 + 201 + [OST_CLK_GLOBAL_TIMER] = { 202 + .init_data = { 203 + .name = "global timer", 204 + .parent_names = ingenic_ost_clk_parents, 205 + .num_parents = ARRAY_SIZE(ingenic_ost_clk_parents), 206 + .ops = &ingenic_ost_global_timer_ops, 207 + .flags = CLK_SET_RATE_UNGATE, 208 + }, 209 + .ostccr_reg = OST_REG_OSTCCR, 210 + }, 211 + }; 212 + 213 + static u64 notrace ingenic_ost_global_timer_read_cntl(void) 214 + { 215 + struct ingenic_ost *ost = ingenic_ost; 216 + unsigned int count; 217 + 218 + count = readl(ost->base + OST_REG_OST2CNTL); 219 + 220 + return count; 221 + } 222 + 223 + static u64 notrace ingenic_ost_clocksource_read(struct clocksource *cs) 224 + { 225 + return ingenic_ost_global_timer_read_cntl(); 226 + } 227 + 228 + static inline struct ingenic_ost *to_ingenic_ost(struct clock_event_device *evt) 229 + { 230 + return container_of(evt, struct ingenic_ost, cevt); 231 + } 232 + 233 + static int ingenic_ost_cevt_set_state_shutdown(struct clock_event_device *evt) 234 + { 235 + struct ingenic_ost *ost = to_ingenic_ost(evt); 236 + 237 + writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR); 238 + 239 + return 0; 240 + } 241 + 242 + static int ingenic_ost_cevt_set_next(unsigned long next, 243 + struct clock_event_device *evt) 244 + { 245 + struct ingenic_ost *ost = to_ingenic_ost(evt); 246 + 247 + writel((u32)~OSTFR_FFLAG, ost->base + OST_REG_OSTFR); 248 + writel(next, ost->base + OST_REG_OST1DFR); 249 + writel(OSTCR_OST1CLR, ost->base + OST_REG_OSTCR); 250 + writel(OSTESR_OST1ENS, ost->base + OST_REG_OSTESR); 251 + writel((u32)~OSTMR_FMASK, ost->base + OST_REG_OSTMR); 252 + 253 + return 0; 254 + } 255 + 256 + static irqreturn_t ingenic_ost_cevt_cb(int irq, void *dev_id) 257 + { 258 + struct clock_event_device *evt = dev_id; 259 + struct ingenic_ost *ost = to_ingenic_ost(evt); 260 + 261 + writel(OSTECR_OST1ENC, ost->base + OST_REG_OSTECR); 262 + 263 + if (evt->event_handler) 264 + evt->event_handler(evt); 265 + 266 + return IRQ_HANDLED; 267 + } 268 + 269 + static int __init ingenic_ost_register_clock(struct ingenic_ost *ost, 270 + unsigned int idx, const struct ingenic_ost_clk_info *info, 271 + struct clk_hw_onecell_data *clocks) 272 + { 273 + struct ingenic_ost_clk *ost_clk; 274 + int val, err; 275 + 276 + ost_clk = kzalloc(sizeof(*ost_clk), GFP_KERNEL); 277 + if (!ost_clk) 278 + return -ENOMEM; 279 + 280 + ost_clk->hw.init = &info->init_data; 281 + ost_clk->idx = idx; 282 + ost_clk->info = info; 283 + ost_clk->ost = ost; 284 + 285 + /* Reset clock divider */ 286 + val = readl(ost->base + info->ostccr_reg); 287 + val &= ~(OSTCCR_PRESCALE1_MASK | OSTCCR_PRESCALE2_MASK); 288 + writel(val, ost->base + info->ostccr_reg); 289 + 290 + err = clk_hw_register(NULL, &ost_clk->hw); 291 + if (err) { 292 + kfree(ost_clk); 293 + return err; 294 + } 295 + 296 + clocks->hws[idx] = &ost_clk->hw; 297 + 298 + return 0; 299 + } 300 + 301 + static struct clk * __init ingenic_ost_get_clock(struct device_node *np, int id) 302 + { 303 + struct of_phandle_args args; 304 + 305 + args.np = np; 306 + args.args_count = 1; 307 + args.args[0] = id; 308 + 309 + return of_clk_get_from_provider(&args); 310 + } 311 + 312 + static int __init ingenic_ost_percpu_timer_init(struct device_node *np, 313 + struct ingenic_ost *ost) 314 + { 315 + unsigned int timer_virq, channel = OST_CLK_PERCPU_TIMER; 316 + unsigned long rate; 317 + int err; 318 + 319 + ost->percpu_timer_clk = ingenic_ost_get_clock(np, channel); 320 + if (IS_ERR(ost->percpu_timer_clk)) 321 + return PTR_ERR(ost->percpu_timer_clk); 322 + 323 + err = clk_prepare_enable(ost->percpu_timer_clk); 324 + if (err) 325 + goto err_clk_put; 326 + 327 + rate = clk_get_rate(ost->percpu_timer_clk); 328 + if (!rate) { 329 + err = -EINVAL; 330 + goto err_clk_disable; 331 + } 332 + 333 + timer_virq = of_irq_get(np, 0); 334 + if (!timer_virq) { 335 + err = -EINVAL; 336 + goto err_clk_disable; 337 + } 338 + 339 + snprintf(ost->name, sizeof(ost->name), "OST percpu timer"); 340 + 341 + err = request_irq(timer_virq, ingenic_ost_cevt_cb, IRQF_TIMER, 342 + ost->name, &ost->cevt); 343 + if (err) 344 + goto err_irq_dispose_mapping; 345 + 346 + ost->cevt.cpumask = cpumask_of(smp_processor_id()); 347 + ost->cevt.features = CLOCK_EVT_FEAT_ONESHOT; 348 + ost->cevt.name = ost->name; 349 + ost->cevt.rating = 400; 350 + ost->cevt.set_state_shutdown = ingenic_ost_cevt_set_state_shutdown; 351 + ost->cevt.set_next_event = ingenic_ost_cevt_set_next; 352 + 353 + clockevents_config_and_register(&ost->cevt, rate, 4, 0xffffffff); 354 + 355 + return 0; 356 + 357 + err_irq_dispose_mapping: 358 + irq_dispose_mapping(timer_virq); 359 + err_clk_disable: 360 + clk_disable_unprepare(ost->percpu_timer_clk); 361 + err_clk_put: 362 + clk_put(ost->percpu_timer_clk); 363 + return err; 364 + } 365 + 366 + static int __init ingenic_ost_global_timer_init(struct device_node *np, 367 + struct ingenic_ost *ost) 368 + { 369 + unsigned int channel = OST_CLK_GLOBAL_TIMER; 370 + struct clocksource *cs = &ost->cs; 371 + unsigned long rate; 372 + int err; 373 + 374 + ost->global_timer_clk = ingenic_ost_get_clock(np, channel); 375 + if (IS_ERR(ost->global_timer_clk)) 376 + return PTR_ERR(ost->global_timer_clk); 377 + 378 + err = clk_prepare_enable(ost->global_timer_clk); 379 + if (err) 380 + goto err_clk_put; 381 + 382 + rate = clk_get_rate(ost->global_timer_clk); 383 + if (!rate) { 384 + err = -EINVAL; 385 + goto err_clk_disable; 386 + } 387 + 388 + /* Clear counter CNT registers */ 389 + writel(OSTCR_OST2CLR, ost->base + OST_REG_OSTCR); 390 + 391 + /* Enable OST channel */ 392 + writel(OSTESR_OST2ENS, ost->base + OST_REG_OSTESR); 393 + 394 + cs->name = "ingenic-ost"; 395 + cs->rating = 400; 396 + cs->flags = CLOCK_SOURCE_IS_CONTINUOUS; 397 + cs->mask = CLOCKSOURCE_MASK(32); 398 + cs->read = ingenic_ost_clocksource_read; 399 + 400 + err = clocksource_register_hz(cs, rate); 401 + if (err) 402 + goto err_clk_disable; 403 + 404 + return 0; 405 + 406 + err_clk_disable: 407 + clk_disable_unprepare(ost->global_timer_clk); 408 + err_clk_put: 409 + clk_put(ost->global_timer_clk); 410 + return err; 411 + } 412 + 413 + static const struct ingenic_soc_info x1000_soc_info = { 414 + .num_channels = 2, 415 + }; 416 + 417 + static const struct of_device_id __maybe_unused ingenic_ost_of_match[] __initconst = { 418 + { .compatible = "ingenic,x1000-ost", .data = &x1000_soc_info, }, 419 + { /* sentinel */ } 420 + }; 421 + 422 + static int __init ingenic_ost_probe(struct device_node *np) 423 + { 424 + const struct of_device_id *id = of_match_node(ingenic_ost_of_match, np); 425 + struct ingenic_ost *ost; 426 + unsigned int i; 427 + int ret; 428 + 429 + ost = kzalloc(sizeof(*ost), GFP_KERNEL); 430 + if (!ost) 431 + return -ENOMEM; 432 + 433 + ost->base = of_io_request_and_map(np, 0, of_node_full_name(np)); 434 + if (IS_ERR(ost->base)) { 435 + pr_err("%s: Failed to map OST registers\n", __func__); 436 + ret = PTR_ERR(ost->base); 437 + goto err_free_ost; 438 + } 439 + 440 + ost->clk = of_clk_get_by_name(np, "ost"); 441 + if (IS_ERR(ost->clk)) { 442 + ret = PTR_ERR(ost->clk); 443 + pr_crit("%s: Cannot get OST clock\n", __func__); 444 + goto err_free_ost; 445 + } 446 + 447 + ret = clk_prepare_enable(ost->clk); 448 + if (ret) { 449 + pr_crit("%s: Unable to enable OST clock\n", __func__); 450 + goto err_put_clk; 451 + } 452 + 453 + ost->soc_info = id->data; 454 + 455 + ost->clocks = kzalloc(struct_size(ost->clocks, hws, ost->soc_info->num_channels), 456 + GFP_KERNEL); 457 + if (!ost->clocks) { 458 + ret = -ENOMEM; 459 + goto err_clk_disable; 460 + } 461 + 462 + ost->clocks->num = ost->soc_info->num_channels; 463 + 464 + for (i = 0; i < ost->clocks->num; i++) { 465 + ret = ingenic_ost_register_clock(ost, i, &ingenic_ost_clk_info[i], ost->clocks); 466 + if (ret) { 467 + pr_crit("%s: Cannot register clock %d\n", __func__, i); 468 + goto err_unregister_ost_clocks; 469 + } 470 + } 471 + 472 + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, ost->clocks); 473 + if (ret) { 474 + pr_crit("%s: Cannot add OF clock provider\n", __func__); 475 + goto err_unregister_ost_clocks; 476 + } 477 + 478 + ingenic_ost = ost; 479 + 480 + return 0; 481 + 482 + err_unregister_ost_clocks: 483 + for (i = 0; i < ost->clocks->num; i++) 484 + if (ost->clocks->hws[i]) 485 + clk_hw_unregister(ost->clocks->hws[i]); 486 + kfree(ost->clocks); 487 + err_clk_disable: 488 + clk_disable_unprepare(ost->clk); 489 + err_put_clk: 490 + clk_put(ost->clk); 491 + err_free_ost: 492 + kfree(ost); 493 + return ret; 494 + } 495 + 496 + static int __init ingenic_ost_init(struct device_node *np) 497 + { 498 + struct ingenic_ost *ost; 499 + unsigned long rate; 500 + int ret; 501 + 502 + ret = ingenic_ost_probe(np); 503 + if (ret) { 504 + pr_crit("%s: Failed to initialize OST clocks: %d\n", __func__, ret); 505 + return ret; 506 + } 507 + 508 + of_node_clear_flag(np, OF_POPULATED); 509 + 510 + ost = ingenic_ost; 511 + if (IS_ERR(ost)) 512 + return PTR_ERR(ost); 513 + 514 + ret = ingenic_ost_global_timer_init(np, ost); 515 + if (ret) { 516 + pr_crit("%s: Unable to init global timer: %x\n", __func__, ret); 517 + goto err_free_ingenic_ost; 518 + } 519 + 520 + ret = ingenic_ost_percpu_timer_init(np, ost); 521 + if (ret) 522 + goto err_ost_global_timer_cleanup; 523 + 524 + /* Register the sched_clock at the end as there's no way to undo it */ 525 + rate = clk_get_rate(ost->global_timer_clk); 526 + sched_clock_register(ingenic_ost_global_timer_read_cntl, 32, rate); 527 + 528 + return 0; 529 + 530 + err_ost_global_timer_cleanup: 531 + clocksource_unregister(&ost->cs); 532 + clk_disable_unprepare(ost->global_timer_clk); 533 + clk_put(ost->global_timer_clk); 534 + err_free_ingenic_ost: 535 + kfree(ost); 536 + return ret; 537 + } 538 + 539 + TIMER_OF_DECLARE(x1000_ost, "ingenic,x1000-ost", ingenic_ost_init);
+125 -59
drivers/clocksource/ingenic-timer.c
··· 1 1 // SPDX-License-Identifier: GPL-2.0 2 2 /* 3 - * JZ47xx SoCs TCU IRQ driver 3 + * Ingenic SoCs TCU IRQ driver 4 4 * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net> 5 + * Copyright (C) 2020 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com> 5 6 */ 6 7 7 8 #include <linux/bitops.h> ··· 16 15 #include <linux/of_address.h> 17 16 #include <linux/of_irq.h> 18 17 #include <linux/of_platform.h> 18 + #include <linux/overflow.h> 19 19 #include <linux/platform_device.h> 20 20 #include <linux/regmap.h> 21 21 #include <linux/sched_clock.h> 22 22 23 23 #include <dt-bindings/clock/ingenic,tcu.h> 24 24 25 + static DEFINE_PER_CPU(call_single_data_t, ingenic_cevt_csd); 26 + 25 27 struct ingenic_soc_info { 26 28 unsigned int num_channels; 27 29 }; 28 30 31 + struct ingenic_tcu_timer { 32 + unsigned int cpu; 33 + unsigned int channel; 34 + struct clock_event_device cevt; 35 + struct clk *clk; 36 + char name[8]; 37 + }; 38 + 29 39 struct ingenic_tcu { 30 40 struct regmap *map; 31 - struct clk *timer_clk, *cs_clk; 32 - unsigned int timer_channel, cs_channel; 33 - struct clock_event_device cevt; 41 + struct device_node *np; 42 + struct clk *cs_clk; 43 + unsigned int cs_channel; 34 44 struct clocksource cs; 35 - char name[4]; 36 45 unsigned long pwm_channels_mask; 46 + struct ingenic_tcu_timer timers[]; 37 47 }; 38 48 39 49 static struct ingenic_tcu *ingenic_tcu; ··· 64 52 return ingenic_tcu_timer_read(); 65 53 } 66 54 67 - static inline struct ingenic_tcu *to_ingenic_tcu(struct clock_event_device *evt) 55 + static inline struct ingenic_tcu * 56 + to_ingenic_tcu(struct ingenic_tcu_timer *timer) 68 57 { 69 - return container_of(evt, struct ingenic_tcu, cevt); 58 + return container_of(timer, struct ingenic_tcu, timers[timer->cpu]); 59 + } 60 + 61 + static inline struct ingenic_tcu_timer * 62 + to_ingenic_tcu_timer(struct clock_event_device *evt) 63 + { 64 + return container_of(evt, struct ingenic_tcu_timer, cevt); 70 65 } 71 66 72 67 static int ingenic_tcu_cevt_set_state_shutdown(struct clock_event_device *evt) 73 68 { 74 - struct ingenic_tcu *tcu = to_ingenic_tcu(evt); 69 + struct ingenic_tcu_timer *timer = to_ingenic_tcu_timer(evt); 70 + struct ingenic_tcu *tcu = to_ingenic_tcu(timer); 75 71 76 - regmap_write(tcu->map, TCU_REG_TECR, BIT(tcu->timer_channel)); 72 + regmap_write(tcu->map, TCU_REG_TECR, BIT(timer->channel)); 77 73 78 74 return 0; 79 75 } ··· 89 69 static int ingenic_tcu_cevt_set_next(unsigned long next, 90 70 struct clock_event_device *evt) 91 71 { 92 - struct ingenic_tcu *tcu = to_ingenic_tcu(evt); 72 + struct ingenic_tcu_timer *timer = to_ingenic_tcu_timer(evt); 73 + struct ingenic_tcu *tcu = to_ingenic_tcu(timer); 93 74 94 75 if (next > 0xffff) 95 76 return -EINVAL; 96 77 97 - regmap_write(tcu->map, TCU_REG_TDFRc(tcu->timer_channel), next); 98 - regmap_write(tcu->map, TCU_REG_TCNTc(tcu->timer_channel), 0); 99 - regmap_write(tcu->map, TCU_REG_TESR, BIT(tcu->timer_channel)); 78 + regmap_write(tcu->map, TCU_REG_TDFRc(timer->channel), next); 79 + regmap_write(tcu->map, TCU_REG_TCNTc(timer->channel), 0); 80 + regmap_write(tcu->map, TCU_REG_TESR, BIT(timer->channel)); 100 81 101 82 return 0; 102 83 } 103 84 85 + static void ingenic_per_cpu_event_handler(void *info) 86 + { 87 + struct clock_event_device *cevt = (struct clock_event_device *) info; 88 + 89 + cevt->event_handler(cevt); 90 + } 91 + 104 92 static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id) 105 93 { 106 - struct clock_event_device *evt = dev_id; 107 - struct ingenic_tcu *tcu = to_ingenic_tcu(evt); 94 + struct ingenic_tcu_timer *timer = dev_id; 95 + struct ingenic_tcu *tcu = to_ingenic_tcu(timer); 96 + call_single_data_t *csd; 108 97 109 - regmap_write(tcu->map, TCU_REG_TECR, BIT(tcu->timer_channel)); 98 + regmap_write(tcu->map, TCU_REG_TECR, BIT(timer->channel)); 110 99 111 - if (evt->event_handler) 112 - evt->event_handler(evt); 100 + if (timer->cevt.event_handler) { 101 + csd = &per_cpu(ingenic_cevt_csd, timer->cpu); 102 + csd->info = (void *) &timer->cevt; 103 + csd->func = ingenic_per_cpu_event_handler; 104 + smp_call_function_single_async(timer->cpu, csd); 105 + } 113 106 114 107 return IRQ_HANDLED; 115 108 } ··· 138 105 return of_clk_get_from_provider(&args); 139 106 } 140 107 141 - static int __init ingenic_tcu_timer_init(struct device_node *np, 142 - struct ingenic_tcu *tcu) 108 + static int ingenic_tcu_setup_cevt(unsigned int cpu) 143 109 { 144 - unsigned int timer_virq, channel = tcu->timer_channel; 110 + struct ingenic_tcu *tcu = ingenic_tcu; 111 + struct ingenic_tcu_timer *timer = &tcu->timers[cpu]; 112 + unsigned int timer_virq; 145 113 struct irq_domain *domain; 146 114 unsigned long rate; 147 115 int err; 148 116 149 - tcu->timer_clk = ingenic_tcu_get_clock(np, channel); 150 - if (IS_ERR(tcu->timer_clk)) 151 - return PTR_ERR(tcu->timer_clk); 117 + timer->clk = ingenic_tcu_get_clock(tcu->np, timer->channel); 118 + if (IS_ERR(timer->clk)) 119 + return PTR_ERR(timer->clk); 152 120 153 - err = clk_prepare_enable(tcu->timer_clk); 121 + err = clk_prepare_enable(timer->clk); 154 122 if (err) 155 123 goto err_clk_put; 156 124 157 - rate = clk_get_rate(tcu->timer_clk); 125 + rate = clk_get_rate(timer->clk); 158 126 if (!rate) { 159 127 err = -EINVAL; 160 128 goto err_clk_disable; 161 129 } 162 130 163 - domain = irq_find_host(np); 131 + domain = irq_find_host(tcu->np); 164 132 if (!domain) { 165 133 err = -ENODEV; 166 134 goto err_clk_disable; 167 135 } 168 136 169 - timer_virq = irq_create_mapping(domain, channel); 137 + timer_virq = irq_create_mapping(domain, timer->channel); 170 138 if (!timer_virq) { 171 139 err = -EINVAL; 172 140 goto err_clk_disable; 173 141 } 174 142 175 - snprintf(tcu->name, sizeof(tcu->name), "TCU"); 143 + snprintf(timer->name, sizeof(timer->name), "TCU%u", timer->channel); 176 144 177 145 err = request_irq(timer_virq, ingenic_tcu_cevt_cb, IRQF_TIMER, 178 - tcu->name, &tcu->cevt); 146 + timer->name, timer); 179 147 if (err) 180 148 goto err_irq_dispose_mapping; 181 149 182 - tcu->cevt.cpumask = cpumask_of(smp_processor_id()); 183 - tcu->cevt.features = CLOCK_EVT_FEAT_ONESHOT; 184 - tcu->cevt.name = tcu->name; 185 - tcu->cevt.rating = 200; 186 - tcu->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown; 187 - tcu->cevt.set_next_event = ingenic_tcu_cevt_set_next; 150 + timer->cpu = smp_processor_id(); 151 + timer->cevt.cpumask = cpumask_of(smp_processor_id()); 152 + timer->cevt.features = CLOCK_EVT_FEAT_ONESHOT; 153 + timer->cevt.name = timer->name; 154 + timer->cevt.rating = 200; 155 + timer->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown; 156 + timer->cevt.set_next_event = ingenic_tcu_cevt_set_next; 188 157 189 - clockevents_config_and_register(&tcu->cevt, rate, 10, 0xffff); 158 + clockevents_config_and_register(&timer->cevt, rate, 10, 0xffff); 190 159 191 160 return 0; 192 161 193 162 err_irq_dispose_mapping: 194 163 irq_dispose_mapping(timer_virq); 195 164 err_clk_disable: 196 - clk_disable_unprepare(tcu->timer_clk); 165 + clk_disable_unprepare(timer->clk); 197 166 err_clk_put: 198 - clk_put(tcu->timer_clk); 167 + clk_put(timer->clk); 199 168 return err; 200 169 } 201 170 ··· 273 238 { 274 239 const struct of_device_id *id = of_match_node(ingenic_tcu_of_match, np); 275 240 const struct ingenic_soc_info *soc_info = id->data; 241 + struct ingenic_tcu_timer *timer; 276 242 struct ingenic_tcu *tcu; 277 243 struct regmap *map; 244 + unsigned int cpu; 245 + int ret, last_bit = -1; 278 246 long rate; 279 - int ret; 280 247 281 248 of_node_clear_flag(np, OF_POPULATED); 282 249 ··· 286 249 if (IS_ERR(map)) 287 250 return PTR_ERR(map); 288 251 289 - tcu = kzalloc(sizeof(*tcu), GFP_KERNEL); 252 + tcu = kzalloc(struct_size(tcu, timers, num_possible_cpus()), 253 + GFP_KERNEL); 290 254 if (!tcu) 291 255 return -ENOMEM; 292 256 293 - /* Enable all TCU channels for PWM use by default except channels 0/1 */ 294 - tcu->pwm_channels_mask = GENMASK(soc_info->num_channels - 1, 2); 257 + /* 258 + * Enable all TCU channels for PWM use by default except channels 0/1, 259 + * and channel 2 if target CPU is JZ4780/X2000 and SMP is selected. 260 + */ 261 + tcu->pwm_channels_mask = GENMASK(soc_info->num_channels - 1, 262 + num_possible_cpus() + 1); 295 263 of_property_read_u32(np, "ingenic,pwm-channels-mask", 296 264 (u32 *)&tcu->pwm_channels_mask); 297 265 298 - /* Verify that we have at least two free channels */ 299 - if (hweight8(tcu->pwm_channels_mask) > soc_info->num_channels - 2) { 266 + /* Verify that we have at least num_possible_cpus() + 1 free channels */ 267 + if (hweight8(tcu->pwm_channels_mask) > 268 + soc_info->num_channels - num_possible_cpus() + 1) { 300 269 pr_crit("%s: Invalid PWM channel mask: 0x%02lx\n", __func__, 301 270 tcu->pwm_channels_mask); 302 271 ret = -EINVAL; ··· 310 267 } 311 268 312 269 tcu->map = map; 270 + tcu->np = np; 313 271 ingenic_tcu = tcu; 314 272 315 - tcu->timer_channel = find_first_zero_bit(&tcu->pwm_channels_mask, 316 - soc_info->num_channels); 273 + for (cpu = 0; cpu < num_possible_cpus(); cpu++) { 274 + timer = &tcu->timers[cpu]; 275 + 276 + timer->cpu = cpu; 277 + timer->channel = find_next_zero_bit(&tcu->pwm_channels_mask, 278 + soc_info->num_channels, 279 + last_bit + 1); 280 + last_bit = timer->channel; 281 + } 282 + 317 283 tcu->cs_channel = find_next_zero_bit(&tcu->pwm_channels_mask, 318 284 soc_info->num_channels, 319 - tcu->timer_channel + 1); 285 + last_bit + 1); 320 286 321 287 ret = ingenic_tcu_clocksource_init(np, tcu); 322 288 if (ret) { ··· 333 281 goto err_free_ingenic_tcu; 334 282 } 335 283 336 - ret = ingenic_tcu_timer_init(np, tcu); 337 - if (ret) 284 + /* Setup clock events on each CPU core */ 285 + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "Ingenic XBurst: online", 286 + ingenic_tcu_setup_cevt, NULL); 287 + if (ret < 0) { 288 + pr_crit("%s: Unable to start CPU timers: %d\n", __func__, ret); 338 289 goto err_tcu_clocksource_cleanup; 290 + } 339 291 340 292 /* Register the sched_clock at the end as there's no way to undo it */ 341 293 rate = clk_get_rate(tcu->cs_clk); ··· 371 315 static int __maybe_unused ingenic_tcu_suspend(struct device *dev) 372 316 { 373 317 struct ingenic_tcu *tcu = dev_get_drvdata(dev); 318 + unsigned int cpu; 374 319 375 320 clk_disable(tcu->cs_clk); 376 - clk_disable(tcu->timer_clk); 321 + 322 + for (cpu = 0; cpu < num_online_cpus(); cpu++) 323 + clk_disable(tcu->timers[cpu].clk); 324 + 377 325 return 0; 378 326 } 379 327 380 328 static int __maybe_unused ingenic_tcu_resume(struct device *dev) 381 329 { 382 330 struct ingenic_tcu *tcu = dev_get_drvdata(dev); 331 + unsigned int cpu; 383 332 int ret; 384 333 385 - ret = clk_enable(tcu->timer_clk); 386 - if (ret) 387 - return ret; 388 - 389 - ret = clk_enable(tcu->cs_clk); 390 - if (ret) { 391 - clk_disable(tcu->timer_clk); 392 - return ret; 334 + for (cpu = 0; cpu < num_online_cpus(); cpu++) { 335 + ret = clk_enable(tcu->timers[cpu].clk); 336 + if (ret) 337 + goto err_timer_clk_disable; 393 338 } 394 339 340 + ret = clk_enable(tcu->cs_clk); 341 + if (ret) 342 + goto err_timer_clk_disable; 343 + 395 344 return 0; 345 + 346 + err_timer_clk_disable: 347 + for (; cpu > 0; cpu--) 348 + clk_disable(tcu->timers[cpu - 1].clk); 349 + return ret; 396 350 } 397 351 398 352 static const struct dev_pm_ops __maybe_unused ingenic_tcu_pm_ops = {
+9 -2
drivers/clocksource/nomadik-mtu.c
··· 186 186 { 187 187 unsigned long rate; 188 188 int ret; 189 + int min_ticks; 189 190 190 191 mtu_base = base; 191 192 ··· 195 194 196 195 /* 197 196 * Tick rate is 2.4MHz for Nomadik and 2.4Mhz, 100MHz or 133 MHz 198 - * for ux500. 197 + * for ux500, and in one specific Ux500 case 32768 Hz. 198 + * 199 199 * Use a divide-by-16 counter if the tick rate is more than 32MHz. 200 200 * At 32 MHz, the timer (with 32 bit counter) can be programmed 201 201 * to wake-up at a max 127s a head in time. Dividing a 2.4 MHz timer ··· 232 230 pr_err("%s: request_irq() failed\n", "Nomadik Timer Tick"); 233 231 nmdk_clkevt.cpumask = cpumask_of(0); 234 232 nmdk_clkevt.irq = irq; 235 - clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); 233 + if (rate < 100000) 234 + min_ticks = 5; 235 + else 236 + min_ticks = 2; 237 + clockevents_config_and_register(&nmdk_clkevt, rate, min_ticks, 238 + 0xffffffffU); 236 239 237 240 mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer; 238 241 mtu_delay_timer.freq = rate;
+1 -1
drivers/clocksource/sh_cmt.c
··· 349 349 350 350 /* 351 351 * According to the sh73a0 user's manual, as CMCNT can be operated 352 - * only by the RCLK (Pseudo 32 KHz), there's one restriction on 352 + * only by the RCLK (Pseudo 32 kHz), there's one restriction on 353 353 * modifying CMCNT register; two RCLK cycles are necessary before 354 354 * this register is either read or any modification of the value 355 355 * it holds is reflected in the LSI's actual operation.
+59 -44
drivers/clocksource/timer-atmel-tcb.c
··· 27 27 * - Some chips support 32 bit counter. A single channel is used for 28 28 * this 32 bit free-running counter. the second channel is not used. 29 29 * 30 - * - The third channel may be used to provide a 16-bit clockevent 31 - * source, used in either periodic or oneshot mode. This runs 32 - * at 32 KiHZ, and can handle delays of up to two seconds. 30 + * - The third channel may be used to provide a clockevent source, used in 31 + * either periodic or oneshot mode. For 16-bit counter its runs at 32 KiHZ, 32 + * and can handle delays of up to two seconds. For 32-bit counters, it runs at 33 + * the same rate as the clocksource 33 34 * 34 35 * REVISIT behavior during system suspend states... we should disable 35 36 * all clocks and save the power. Easily done for clockevent devices, ··· 47 46 bool clken; 48 47 } tcb_cache[3]; 49 48 static u32 bmr_cache; 49 + 50 + static const u8 atmel_tcb_divisors[] = { 2, 8, 32, 128 }; 50 51 51 52 static u64 tc_get_cycles(struct clocksource *cs) 52 53 { ··· 146 143 struct tc_clkevt_device { 147 144 struct clock_event_device clkevt; 148 145 struct clk *clk; 146 + u32 rate; 149 147 void __iomem *regs; 150 148 }; 151 149 ··· 155 151 return container_of(clkevt, struct tc_clkevt_device, clkevt); 156 152 } 157 153 158 - /* For now, we always use the 32K clock ... this optimizes for NO_HZ, 159 - * because using one of the divided clocks would usually mean the 160 - * tick rate can never be less than several dozen Hz (vs 0.5 Hz). 161 - * 162 - * A divided clock could be good for high resolution timers, since 163 - * 30.5 usec resolution can seem "low". 164 - */ 165 154 static u32 timer_clock; 166 155 167 156 static int tc_shutdown(struct clock_event_device *d) ··· 180 183 181 184 clk_enable(tcd->clk); 182 185 183 - /* slow clock, count up to RC, then irq and stop */ 186 + /* count up to RC, then irq and stop */ 184 187 writel(timer_clock | ATMEL_TC_CPCSTOP | ATMEL_TC_WAVE | 185 188 ATMEL_TC_WAVESEL_UP_AUTO, regs + ATMEL_TC_REG(2, CMR)); 186 189 writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); ··· 202 205 */ 203 206 clk_enable(tcd->clk); 204 207 205 - /* slow clock, count up to RC, then irq and restart */ 208 + /* count up to RC, then irq and restart */ 206 209 writel(timer_clock | ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO, 207 210 regs + ATMEL_TC_REG(2, CMR)); 208 - writel((32768 + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); 211 + writel((tcd->rate + HZ / 2) / HZ, tcaddr + ATMEL_TC_REG(2, RC)); 209 212 210 213 /* Enable clock and interrupts on RC compare */ 211 214 writel(ATMEL_TC_CPCS, regs + ATMEL_TC_REG(2, IER)); ··· 253 256 return IRQ_NONE; 254 257 } 255 258 256 - static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) 259 + static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx) 257 260 { 258 261 int ret; 259 262 struct clk *t2_clk = tc->clk[2]; 260 263 int irq = tc->irq[2]; 261 - 262 - ret = clk_prepare_enable(tc->slow_clk); 263 - if (ret) 264 - return ret; 264 + int bits = tc->tcb_config->counter_width; 265 265 266 266 /* try to enable t2 clk to avoid future errors in mode change */ 267 267 ret = clk_prepare_enable(t2_clk); 268 - if (ret) { 269 - clk_disable_unprepare(tc->slow_clk); 268 + if (ret) 270 269 return ret; 271 - } 272 - 273 - clk_disable(t2_clk); 274 270 275 271 clkevt.regs = tc->regs; 276 272 clkevt.clk = t2_clk; 277 273 278 - timer_clock = clk32k_divisor_idx; 274 + if (bits == 32) { 275 + timer_clock = divisor_idx; 276 + clkevt.rate = clk_get_rate(t2_clk) / atmel_tcb_divisors[divisor_idx]; 277 + } else { 278 + ret = clk_prepare_enable(tc->slow_clk); 279 + if (ret) { 280 + clk_disable_unprepare(t2_clk); 281 + return ret; 282 + } 283 + 284 + clkevt.rate = clk_get_rate(tc->slow_clk); 285 + timer_clock = ATMEL_TC_TIMER_CLOCK5; 286 + } 287 + 288 + clk_disable(t2_clk); 279 289 280 290 clkevt.clkevt.cpumask = cpumask_of(0); 281 291 282 292 ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt); 283 293 if (ret) { 284 294 clk_unprepare(t2_clk); 285 - clk_disable_unprepare(tc->slow_clk); 295 + if (bits != 32) 296 + clk_disable_unprepare(tc->slow_clk); 286 297 return ret; 287 298 } 288 299 289 - clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); 300 + clockevents_config_and_register(&clkevt.clkevt, clkevt.rate, 1, BIT(bits) - 1); 290 301 291 302 return ret; 292 303 } 293 304 294 305 #else /* !CONFIG_GENERIC_CLOCKEVENTS */ 295 306 296 - static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) 307 + static int __init setup_clkevents(struct atmel_tc *tc, int divisor_idx) 297 308 { 298 309 /* NOTHING */ 299 310 return 0; ··· 351 346 writel(ATMEL_TC_SYNC, tcaddr + ATMEL_TC_BCR); 352 347 } 353 348 354 - static const u8 atmel_tcb_divisors[5] = { 2, 8, 32, 128, 0, }; 349 + static struct atmel_tcb_config tcb_rm9200_config = { 350 + .counter_width = 16, 351 + }; 352 + 353 + static struct atmel_tcb_config tcb_sam9x5_config = { 354 + .counter_width = 32, 355 + }; 356 + 357 + static struct atmel_tcb_config tcb_sama5d2_config = { 358 + .counter_width = 32, 359 + .has_gclk = 1, 360 + }; 355 361 356 362 static const struct of_device_id atmel_tcb_of_match[] = { 357 - { .compatible = "atmel,at91rm9200-tcb", .data = (void *)16, }, 358 - { .compatible = "atmel,at91sam9x5-tcb", .data = (void *)32, }, 363 + { .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, 364 + { .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, 365 + { .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, }, 359 366 { /* sentinel */ } 360 367 }; 361 368 ··· 379 362 u64 (*tc_sched_clock)(void); 380 363 u32 rate, divided_rate = 0; 381 364 int best_divisor_idx = -1; 382 - int clk32k_divisor_idx = -1; 383 365 int bits; 384 366 int i; 385 367 int ret; ··· 415 399 } 416 400 417 401 match = of_match_node(atmel_tcb_of_match, node->parent); 418 - bits = (uintptr_t)match->data; 402 + if (!match) 403 + return -ENODEV; 404 + 405 + tc.tcb_config = match->data; 406 + bits = tc.tcb_config->counter_width; 419 407 420 408 for (i = 0; i < ARRAY_SIZE(tc.irq); i++) 421 409 writel(ATMEL_TC_ALL_IRQ, tc.regs + ATMEL_TC_REG(i, IDR)); ··· 432 412 433 413 /* How fast will we be counting? Pick something over 5 MHz. */ 434 414 rate = (u32) clk_get_rate(t0_clk); 435 - for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); i++) { 415 + i = 0; 416 + if (tc.tcb_config->has_gclk) 417 + i = 1; 418 + for (; i < ARRAY_SIZE(atmel_tcb_divisors); i++) { 436 419 unsigned divisor = atmel_tcb_divisors[i]; 437 420 unsigned tmp; 438 421 439 - /* remember 32 KiHz clock for later */ 440 - if (!divisor) { 441 - clk32k_divisor_idx = i; 442 - continue; 443 - } 444 - 445 422 tmp = rate / divisor; 446 423 pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp); 447 - if (best_divisor_idx > 0) { 448 - if (tmp < 5 * 1000 * 1000) 449 - continue; 450 - } 424 + if ((best_divisor_idx >= 0) && (tmp < 5 * 1000 * 1000)) 425 + break; 451 426 divided_rate = tmp; 452 427 best_divisor_idx = i; 453 428 } ··· 482 467 goto err_disable_t1; 483 468 484 469 /* channel 2: periodic and oneshot timer support */ 485 - ret = setup_clkevents(&tc, clk32k_divisor_idx); 470 + ret = setup_clkevents(&tc, best_divisor_idx); 486 471 if (ret) 487 472 goto err_unregister_clksrc; 488 473
+1 -1
drivers/clocksource/timer-ti-32k.c
··· 21 21 * Roughly modelled after the OMAP1 MPU timer code. 22 22 * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com> 23 23 * 24 - * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com 24 + * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com 25 25 */ 26 26 27 27 #include <linux/clk.h>
+1 -1
drivers/clocksource/timer-ti-dm.c
··· 4 4 * 5 5 * OMAP Dual-Mode Timers 6 6 * 7 - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ 7 + * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com/ 8 8 * Tarun Kanti DebBarma <tarun.kanti@ti.com> 9 9 * Thara Gopinath <thara@ti.com> 10 10 *
+12
include/dt-bindings/clock/ingenic,sysost.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * This header provides clock numbers for the ingenic,tcu DT binding. 4 + */ 5 + 6 + #ifndef __DT_BINDINGS_CLOCK_INGENIC_OST_H__ 7 + #define __DT_BINDINGS_CLOCK_INGENIC_OST_H__ 8 + 9 + #define OST_CLK_PERCPU_TIMER 0 10 + #define OST_CLK_GLOBAL_TIMER 1 11 + 12 + #endif /* __DT_BINDINGS_CLOCK_INGENIC_OST_H__ */
+5
include/soc/at91/atmel_tcb.h
··· 36 36 /** 37 37 * struct atmel_tcb_config - SoC data for a Timer/Counter Block 38 38 * @counter_width: size in bits of a timer counter register 39 + * @has_gclk: boolean indicating if a timer counter has a generic clock 40 + * @has_qdec: boolean indicating if a timer counter has a quadrature 41 + * decoder. 39 42 */ 40 43 struct atmel_tcb_config { 41 44 size_t counter_width; 45 + bool has_gclk; 46 + bool has_qdec; 42 47 }; 43 48 44 49 /**