* [PATCH v2 0/6] clocksource: rework Atmel TCB timer driver @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel Hi, This series gets back on the TCB drivers rework. It introduces a new driver to handle the clocksource and clockevent devices. As a reminder, this is necessary because: - the current tcb_clksrc driver is probed too late to be able to be used at boot and we now have SoCs that don't have a PIT. They currently are not able to boot a mainline kernel. - using the PIT doesn't work well with preempt-rt because its interrupt is shared (in particular with the UART and their interrupt flags are incompatible) - the current solution is wasting some TCB channels The plan is to get this driver upstream, then convert the TCB PWM driver to be able to get rid of the tcb_clksrc driver along with atmel_tclib. I decided to leave out the clocksource/clockevent selection for now as it seems the discussion is going nowhere. We can get back to that later Main changes in v2: - use direct IO instead of regmap when accessing channel specific registers to avoid the regmap locking - implement suspend/resume Alexandre Belloni (6): ARM: at91: add TCB registers definitions clocksource/drivers: Add a new driver for the Atmel ARM TC blocks clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT ARM: configs: at91: use new TCB timer driver ARM: configs: at91: sama5: unselect ATMEL_PIT ARM: configs: at91: at91_dt unselect ATMEL_PIT arch/arm/configs/at91_dt_defconfig | 2 +- arch/arm/configs/sama5_defconfig | 2 +- drivers/clocksource/Kconfig | 23 +- drivers/clocksource/Makefile | 3 +- drivers/clocksource/timer-atmel-tcb.c | 608 ++++++++++++++++++++++++++++++++++ include/soc/at91/atmel_tcb.h | 229 +++++++++++++ 6 files changed, 863 insertions(+), 4 deletions(-) create mode 100644 drivers/clocksource/timer-atmel-tcb.c create mode 100644 include/soc/at91/atmel_tcb.h -- 2.15.1 ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 0/6] clocksource: rework Atmel TCB timer driver @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni Hi, This series gets back on the TCB drivers rework. It introduces a new driver to handle the clocksource and clockevent devices. As a reminder, this is necessary because: - the current tcb_clksrc driver is probed too late to be able to be used at boot and we now have SoCs that don't have a PIT. They currently are not able to boot a mainline kernel. - using the PIT doesn't work well with preempt-rt because its interrupt is shared (in particular with the UART and their interrupt flags are incompatible) - the current solution is wasting some TCB channels The plan is to get this driver upstream, then convert the TCB PWM driver to be able to get rid of the tcb_clksrc driver along with atmel_tclib. I decided to leave out the clocksource/clockevent selection for now as it seems the discussion is going nowhere. We can get back to that later Main changes in v2: - use direct IO instead of regmap when accessing channel specific registers to avoid the regmap locking - implement suspend/resume Alexandre Belloni (6): ARM: at91: add TCB registers definitions clocksource/drivers: Add a new driver for the Atmel ARM TC blocks clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT ARM: configs: at91: use new TCB timer driver ARM: configs: at91: sama5: unselect ATMEL_PIT ARM: configs: at91: at91_dt unselect ATMEL_PIT arch/arm/configs/at91_dt_defconfig | 2 +- arch/arm/configs/sama5_defconfig | 2 +- drivers/clocksource/Kconfig | 23 +- drivers/clocksource/Makefile | 3 +- drivers/clocksource/timer-atmel-tcb.c | 608 ++++++++++++++++++++++++++++++++++ include/soc/at91/atmel_tcb.h | 229 +++++++++++++ 6 files changed, 863 insertions(+), 4 deletions(-) create mode 100644 drivers/clocksource/timer-atmel-tcb.c create mode 100644 include/soc/at91/atmel_tcb.h -- 2.15.1 ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 1/6] ARM: at91: add TCB registers definitions 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel Add registers and bits definitions for the timer counter blocks found on Atmel ARM SoCs. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- include/soc/at91/atmel_tcb.h | 229 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 include/soc/at91/atmel_tcb.h diff --git a/include/soc/at91/atmel_tcb.h b/include/soc/at91/atmel_tcb.h new file mode 100644 index 000000000000..f48e60f8ab92 --- /dev/null +++ b/include/soc/at91/atmel_tcb.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2016 Atmel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SOC_ATMEL_TCB_H +#define __SOC_ATMEL_TCB_H + +/* Channel registers */ +#define ATMEL_TC_COFFS(c) ((c) * 0x40) +#define ATMEL_TC_CCR(c) ATMEL_TC_COFFS(c) +#define ATMEL_TC_CMR(c) (ATMEL_TC_COFFS(c) + 0x4) +#define ATMEL_TC_SMMR(c) (ATMEL_TC_COFFS(c) + 0x8) +#define ATMEL_TC_RAB(c) (ATMEL_TC_COFFS(c) + 0xc) +#define ATMEL_TC_CV(c) (ATMEL_TC_COFFS(c) + 0x10) +#define ATMEL_TC_RA(c) (ATMEL_TC_COFFS(c) + 0x14) +#define ATMEL_TC_RB(c) (ATMEL_TC_COFFS(c) + 0x18) +#define ATMEL_TC_RC(c) (ATMEL_TC_COFFS(c) + 0x1c) +#define ATMEL_TC_SR(c) (ATMEL_TC_COFFS(c) + 0x20) +#define ATMEL_TC_IER(c) (ATMEL_TC_COFFS(c) + 0x24) +#define ATMEL_TC_IDR(c) (ATMEL_TC_COFFS(c) + 0x28) +#define ATMEL_TC_IMR(c) (ATMEL_TC_COFFS(c) + 0x2c) +#define ATMEL_TC_EMR(c) (ATMEL_TC_COFFS(c) + 0x30) + +/* Block registers */ +#define ATMEL_TC_BCR 0xc0 +#define ATMEL_TC_BMR 0xc4 +#define ATMEL_TC_QIER 0xc8 +#define ATMEL_TC_QIDR 0xcc +#define ATMEL_TC_QIMR 0xd0 +#define ATMEL_TC_QISR 0xd4 +#define ATMEL_TC_FMR 0xd8 +#define ATMEL_TC_WPMR 0xe4 + +/* CCR fields */ +#define ATMEL_TC_CCR_CLKEN BIT(0) +#define ATMEL_TC_CCR_CLKDIS BIT(1) +#define ATMEL_TC_CCR_SWTRG BIT(2) + +/* Common CMR fields */ +#define ATMEL_TC_CMR_TCLKS_MSK GENMASK(2, 0) +#define ATMEL_TC_CMR_TCLK(x) (x) +#define ATMEL_TC_CMR_XC(x) ((x) + 5) +#define ATMEL_TC_CMR_CLKI BIT(3) +#define ATMEL_TC_CMR_BURST_MSK GENMASK(5, 4) +#define ATMEL_TC_CMR_BURST_XC(x) (((x) + 1) << 4) +#define ATMEL_TC_CMR_WAVE BIT(15) + +/* Capture mode CMR fields */ +#define ATMEL_TC_CMR_LDBSTOP BIT(6) +#define ATMEL_TC_CMR_LDBDIS BIT(7) +#define ATMEL_TC_CMR_ETRGEDG_MSK GENMASK(9, 8) +#define ATMEL_TC_CMR_ETRGEDG_NONE (0 << 8) +#define ATMEL_TC_CMR_ETRGEDG_RISING (1 << 8) +#define ATMEL_TC_CMR_ETRGEDG_FALLING (2 << 8) +#define ATMEL_TC_CMR_ETRGEDG_BOTH (3 << 8) +#define ATMEL_TC_CMR_ABETRG BIT(10) +#define ATMEL_TC_CMR_CPCTRG BIT(14) +#define ATMEL_TC_CMR_LDRA_MSK GENMASK(17, 16) +#define ATMEL_TC_CMR_LDRA_NONE (0 << 16) +#define ATMEL_TC_CMR_LDRA_RISING (1 << 16) +#define ATMEL_TC_CMR_LDRA_FALLING (2 << 16) +#define ATMEL_TC_CMR_LDRA_BOTH (3 << 16) +#define ATMEL_TC_CMR_LDRB_MSK GENMASK(19, 18) +#define ATMEL_TC_CMR_LDRB_NONE (0 << 18) +#define ATMEL_TC_CMR_LDRB_RISING (1 << 18) +#define ATMEL_TC_CMR_LDRB_FALLING (2 << 18) +#define ATMEL_TC_CMR_LDRB_BOTH (3 << 18) +#define ATMEL_TC_CMR_SBSMPLR_MSK GENMASK(22, 20) +#define ATMEL_TC_CMR_SBSMPLR(x) ((x) << 20) + +/* Waveform mode CMR fields */ +#define ATMEL_TC_CMR_CPCSTOP BIT(6) +#define ATMEL_TC_CMR_CPCDIS BIT(7) +#define ATMEL_TC_CMR_EEVTEDG_MSK GENMASK(9, 8) +#define ATMEL_TC_CMR_EEVTEDG_NONE (0 << 8) +#define ATMEL_TC_CMR_EEVTEDG_RISING (1 << 8) +#define ATMEL_TC_CMR_EEVTEDG_FALLING (2 << 8) +#define ATMEL_TC_CMR_EEVTEDG_BOTH (3 << 8) +#define ATMEL_TC_CMR_EEVT_MSK GENMASK(11, 10) +#define ATMEL_TC_CMR_EEVT_XC(x) (((x) + 1) << 10) +#define ATMEL_TC_CMR_ENETRG BIT(12) +#define ATMEL_TC_CMR_WAVESEL_MSK GENMASK(14, 13) +#define ATMEL_TC_CMR_WAVESEL_UP (0 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPDOWN (1 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPRC (2 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPDOWNRC (3 << 13) +#define ATMEL_TC_CMR_ACPA_MSK GENMASK(17, 16) +#define ATMEL_TC_CMR_ACPA(a) (ATMEL_TC_CMR_ACTION_##a << 16) +#define ATMEL_TC_CMR_ACPC_MSK GENMASK(19, 18) +#define ATMEL_TC_CMR_ACPC(a) (ATMEL_TC_CMR_ACTION_##a << 18) +#define ATMEL_TC_CMR_AEEVT_MSK GENMASK(21, 20) +#define ATMEL_TC_CMR_AEEVT(a) (ATMEL_TC_CMR_ACTION_##a << 20) +#define ATMEL_TC_CMR_ASWTRG_MSK GENMASK(23, 22) +#define ATMEL_TC_CMR_ASWTRG(a) (ATMEL_TC_CMR_ACTION_##a << 22) +#define ATMEL_TC_CMR_BCPB_MSK GENMASK(25, 24) +#define ATMEL_TC_CMR_BCPB(a) (ATMEL_TC_CMR_ACTION_##a << 24) +#define ATMEL_TC_CMR_BCPC_MSK GENMASK(27, 26) +#define ATMEL_TC_CMR_BCPC(a) (ATMEL_TC_CMR_ACTION_##a << 26) +#define ATMEL_TC_CMR_BEEVT_MSK GENMASK(29, 28) +#define ATMEL_TC_CMR_BEEVT(a) (ATMEL_TC_CMR_ACTION_##a << 28) +#define ATMEL_TC_CMR_BSWTRG_MSK GENMASK(31, 30) +#define ATMEL_TC_CMR_BSWTRG(a) (ATMEL_TC_CMR_ACTION_##a << 30) +#define ATMEL_TC_CMR_ACTION_NONE 0 +#define ATMEL_TC_CMR_ACTION_SET 1 +#define ATMEL_TC_CMR_ACTION_CLEAR 2 +#define ATMEL_TC_CMR_ACTION_TOGGLE 3 + +/* SMMR fields */ +#define ATMEL_TC_SMMR_GCEN BIT(0) +#define ATMEL_TC_SMMR_DOWN BIT(1) + +/* SR/IER/IDR/IMR fields */ +#define ATMEL_TC_COVFS BIT(0) +#define ATMEL_TC_LOVRS BIT(1) +#define ATMEL_TC_CPAS BIT(2) +#define ATMEL_TC_CPBS BIT(3) +#define ATMEL_TC_CPCS BIT(4) +#define ATMEL_TC_LDRAS BIT(5) +#define ATMEL_TC_LDRBS BIT(6) +#define ATMEL_TC_ETRGS BIT(7) +#define ATMEL_TC_CLKSTA BIT(16) +#define ATMEL_TC_MTIOA BIT(17) +#define ATMEL_TC_MTIOB BIT(18) + +/* EMR fields */ +#define ATMEL_TC_EMR_TRIGSRCA_MSK GENMASK(1, 0) +#define ATMEL_TC_EMR_TRIGSRCA_TIOA 0 +#define ATMEL_TC_EMR_TRIGSRCA_PWMX 1 +#define ATMEL_TC_EMR_TRIGSRCB_MSK GENMASK(5, 4) +#define ATMEL_TC_EMR_TRIGSRCB_TIOB (0 << 4) +#define ATMEL_TC_EMR_TRIGSRCB_PWM (1 << 4) +#define ATMEL_TC_EMR_NOCLKDIV BIT(8) + +/* BCR fields */ +#define ATMEL_TC_BCR_SYNC BIT(0) + +/* BMR fields */ +#define ATMEL_TC_BMR_TCXC_MSK(c) GENMASK(((c) * 2) + 1, (c) * 2) +#define ATMEL_TC_BMR_TCXC(x, c) ((x) << (2 * (c))) +#define ATMEL_TC_BMR_QDEN BIT(8) +#define ATMEL_TC_BMR_POSEN BIT(9) +#define ATMEL_TC_BMR_SPEEDEN BIT(10) +#define ATMEL_TC_BMR_QDTRANS BIT(11) +#define ATMEL_TC_BMR_EDGPHA BIT(12) +#define ATMEL_TC_BMR_INVA BIT(13) +#define ATMEL_TC_BMR_INVB BIT(14) +#define ATMEL_TC_BMR_INVIDX BIT(15) +#define ATMEL_TC_BMR_SWAP BIT(16) +#define ATMEL_TC_BMR_IDXPHB BIT(17) +#define ATMEL_TC_BMR_AUTOC BIT(18) +#define ATMEL_TC_MAXFILT_MSK GENMASK(25, 20) +#define ATMEL_TC_MAXFILT(x) (((x) - 1) << 20) +#define ATMEL_TC_MAXCMP_MSK GENMASK(29, 26) +#define ATMEL_TC_MAXCMP(x) ((x) << 26) + +/* QEDC fields */ +#define ATMEL_TC_QEDC_IDX BIT(0) +#define ATMEL_TC_QEDC_DIRCHG BIT(1) +#define ATMEL_TC_QEDC_QERR BIT(2) +#define ATMEL_TC_QEDC_MPE BIT(3) +#define ATMEL_TC_QEDC_DIR BIT(8) + +/* FMR fields */ +#define ATMEL_TC_FMR_ENCF(x) BIT(x) + +/* WPMR fields */ +#define ATMEL_TC_WPMR_WPKEY (0x54494d << 8) +#define ATMEL_TC_WPMR_WPEN BIT(0) + +static inline struct clk *tcb_clk_get(struct device_node *node, int channel) +{ + struct clk *clk; + char clk_name[] = "t0_clk"; + + clk_name[1] += channel; + clk = of_clk_get_by_name(node->parent, clk_name); + if (!IS_ERR(clk)) + return clk; + + return of_clk_get_by_name(node->parent, "t0_clk"); +} + +static inline int tcb_irq_get(struct device_node *node, int channel) +{ + int irq; + + irq = of_irq_get(node->parent, channel); + if (irq > 0) + return irq; + + return of_irq_get(node->parent, 0); +} + +static const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, }; + +struct atmel_tcb_info { + int bits; +}; + +static const struct atmel_tcb_info atmel_tcb_infos[] = { + { .bits = 16 }, + { .bits = 32 }, +}; + +static const struct of_device_id atmel_tcb_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-tcb", + .data = &atmel_tcb_infos[0], + }, { + .compatible = "atmel,at91sam9x5-tcb", + .data = &atmel_tcb_infos[1], + }, { + /* sentinel */ + } +}; + +#endif /* __SOC_ATMEL_TCB_H */ -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 1/6] ARM: at91: add TCB registers definitions @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni Add registers and bits definitions for the timer counter blocks found on Atmel ARM SoCs. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- include/soc/at91/atmel_tcb.h | 229 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 include/soc/at91/atmel_tcb.h diff --git a/include/soc/at91/atmel_tcb.h b/include/soc/at91/atmel_tcb.h new file mode 100644 index 000000000000..f48e60f8ab92 --- /dev/null +++ b/include/soc/at91/atmel_tcb.h @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2016 Atmel + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __SOC_ATMEL_TCB_H +#define __SOC_ATMEL_TCB_H + +/* Channel registers */ +#define ATMEL_TC_COFFS(c) ((c) * 0x40) +#define ATMEL_TC_CCR(c) ATMEL_TC_COFFS(c) +#define ATMEL_TC_CMR(c) (ATMEL_TC_COFFS(c) + 0x4) +#define ATMEL_TC_SMMR(c) (ATMEL_TC_COFFS(c) + 0x8) +#define ATMEL_TC_RAB(c) (ATMEL_TC_COFFS(c) + 0xc) +#define ATMEL_TC_CV(c) (ATMEL_TC_COFFS(c) + 0x10) +#define ATMEL_TC_RA(c) (ATMEL_TC_COFFS(c) + 0x14) +#define ATMEL_TC_RB(c) (ATMEL_TC_COFFS(c) + 0x18) +#define ATMEL_TC_RC(c) (ATMEL_TC_COFFS(c) + 0x1c) +#define ATMEL_TC_SR(c) (ATMEL_TC_COFFS(c) + 0x20) +#define ATMEL_TC_IER(c) (ATMEL_TC_COFFS(c) + 0x24) +#define ATMEL_TC_IDR(c) (ATMEL_TC_COFFS(c) + 0x28) +#define ATMEL_TC_IMR(c) (ATMEL_TC_COFFS(c) + 0x2c) +#define ATMEL_TC_EMR(c) (ATMEL_TC_COFFS(c) + 0x30) + +/* Block registers */ +#define ATMEL_TC_BCR 0xc0 +#define ATMEL_TC_BMR 0xc4 +#define ATMEL_TC_QIER 0xc8 +#define ATMEL_TC_QIDR 0xcc +#define ATMEL_TC_QIMR 0xd0 +#define ATMEL_TC_QISR 0xd4 +#define ATMEL_TC_FMR 0xd8 +#define ATMEL_TC_WPMR 0xe4 + +/* CCR fields */ +#define ATMEL_TC_CCR_CLKEN BIT(0) +#define ATMEL_TC_CCR_CLKDIS BIT(1) +#define ATMEL_TC_CCR_SWTRG BIT(2) + +/* Common CMR fields */ +#define ATMEL_TC_CMR_TCLKS_MSK GENMASK(2, 0) +#define ATMEL_TC_CMR_TCLK(x) (x) +#define ATMEL_TC_CMR_XC(x) ((x) + 5) +#define ATMEL_TC_CMR_CLKI BIT(3) +#define ATMEL_TC_CMR_BURST_MSK GENMASK(5, 4) +#define ATMEL_TC_CMR_BURST_XC(x) (((x) + 1) << 4) +#define ATMEL_TC_CMR_WAVE BIT(15) + +/* Capture mode CMR fields */ +#define ATMEL_TC_CMR_LDBSTOP BIT(6) +#define ATMEL_TC_CMR_LDBDIS BIT(7) +#define ATMEL_TC_CMR_ETRGEDG_MSK GENMASK(9, 8) +#define ATMEL_TC_CMR_ETRGEDG_NONE (0 << 8) +#define ATMEL_TC_CMR_ETRGEDG_RISING (1 << 8) +#define ATMEL_TC_CMR_ETRGEDG_FALLING (2 << 8) +#define ATMEL_TC_CMR_ETRGEDG_BOTH (3 << 8) +#define ATMEL_TC_CMR_ABETRG BIT(10) +#define ATMEL_TC_CMR_CPCTRG BIT(14) +#define ATMEL_TC_CMR_LDRA_MSK GENMASK(17, 16) +#define ATMEL_TC_CMR_LDRA_NONE (0 << 16) +#define ATMEL_TC_CMR_LDRA_RISING (1 << 16) +#define ATMEL_TC_CMR_LDRA_FALLING (2 << 16) +#define ATMEL_TC_CMR_LDRA_BOTH (3 << 16) +#define ATMEL_TC_CMR_LDRB_MSK GENMASK(19, 18) +#define ATMEL_TC_CMR_LDRB_NONE (0 << 18) +#define ATMEL_TC_CMR_LDRB_RISING (1 << 18) +#define ATMEL_TC_CMR_LDRB_FALLING (2 << 18) +#define ATMEL_TC_CMR_LDRB_BOTH (3 << 18) +#define ATMEL_TC_CMR_SBSMPLR_MSK GENMASK(22, 20) +#define ATMEL_TC_CMR_SBSMPLR(x) ((x) << 20) + +/* Waveform mode CMR fields */ +#define ATMEL_TC_CMR_CPCSTOP BIT(6) +#define ATMEL_TC_CMR_CPCDIS BIT(7) +#define ATMEL_TC_CMR_EEVTEDG_MSK GENMASK(9, 8) +#define ATMEL_TC_CMR_EEVTEDG_NONE (0 << 8) +#define ATMEL_TC_CMR_EEVTEDG_RISING (1 << 8) +#define ATMEL_TC_CMR_EEVTEDG_FALLING (2 << 8) +#define ATMEL_TC_CMR_EEVTEDG_BOTH (3 << 8) +#define ATMEL_TC_CMR_EEVT_MSK GENMASK(11, 10) +#define ATMEL_TC_CMR_EEVT_XC(x) (((x) + 1) << 10) +#define ATMEL_TC_CMR_ENETRG BIT(12) +#define ATMEL_TC_CMR_WAVESEL_MSK GENMASK(14, 13) +#define ATMEL_TC_CMR_WAVESEL_UP (0 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPDOWN (1 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPRC (2 << 13) +#define ATMEL_TC_CMR_WAVESEL_UPDOWNRC (3 << 13) +#define ATMEL_TC_CMR_ACPA_MSK GENMASK(17, 16) +#define ATMEL_TC_CMR_ACPA(a) (ATMEL_TC_CMR_ACTION_##a << 16) +#define ATMEL_TC_CMR_ACPC_MSK GENMASK(19, 18) +#define ATMEL_TC_CMR_ACPC(a) (ATMEL_TC_CMR_ACTION_##a << 18) +#define ATMEL_TC_CMR_AEEVT_MSK GENMASK(21, 20) +#define ATMEL_TC_CMR_AEEVT(a) (ATMEL_TC_CMR_ACTION_##a << 20) +#define ATMEL_TC_CMR_ASWTRG_MSK GENMASK(23, 22) +#define ATMEL_TC_CMR_ASWTRG(a) (ATMEL_TC_CMR_ACTION_##a << 22) +#define ATMEL_TC_CMR_BCPB_MSK GENMASK(25, 24) +#define ATMEL_TC_CMR_BCPB(a) (ATMEL_TC_CMR_ACTION_##a << 24) +#define ATMEL_TC_CMR_BCPC_MSK GENMASK(27, 26) +#define ATMEL_TC_CMR_BCPC(a) (ATMEL_TC_CMR_ACTION_##a << 26) +#define ATMEL_TC_CMR_BEEVT_MSK GENMASK(29, 28) +#define ATMEL_TC_CMR_BEEVT(a) (ATMEL_TC_CMR_ACTION_##a << 28) +#define ATMEL_TC_CMR_BSWTRG_MSK GENMASK(31, 30) +#define ATMEL_TC_CMR_BSWTRG(a) (ATMEL_TC_CMR_ACTION_##a << 30) +#define ATMEL_TC_CMR_ACTION_NONE 0 +#define ATMEL_TC_CMR_ACTION_SET 1 +#define ATMEL_TC_CMR_ACTION_CLEAR 2 +#define ATMEL_TC_CMR_ACTION_TOGGLE 3 + +/* SMMR fields */ +#define ATMEL_TC_SMMR_GCEN BIT(0) +#define ATMEL_TC_SMMR_DOWN BIT(1) + +/* SR/IER/IDR/IMR fields */ +#define ATMEL_TC_COVFS BIT(0) +#define ATMEL_TC_LOVRS BIT(1) +#define ATMEL_TC_CPAS BIT(2) +#define ATMEL_TC_CPBS BIT(3) +#define ATMEL_TC_CPCS BIT(4) +#define ATMEL_TC_LDRAS BIT(5) +#define ATMEL_TC_LDRBS BIT(6) +#define ATMEL_TC_ETRGS BIT(7) +#define ATMEL_TC_CLKSTA BIT(16) +#define ATMEL_TC_MTIOA BIT(17) +#define ATMEL_TC_MTIOB BIT(18) + +/* EMR fields */ +#define ATMEL_TC_EMR_TRIGSRCA_MSK GENMASK(1, 0) +#define ATMEL_TC_EMR_TRIGSRCA_TIOA 0 +#define ATMEL_TC_EMR_TRIGSRCA_PWMX 1 +#define ATMEL_TC_EMR_TRIGSRCB_MSK GENMASK(5, 4) +#define ATMEL_TC_EMR_TRIGSRCB_TIOB (0 << 4) +#define ATMEL_TC_EMR_TRIGSRCB_PWM (1 << 4) +#define ATMEL_TC_EMR_NOCLKDIV BIT(8) + +/* BCR fields */ +#define ATMEL_TC_BCR_SYNC BIT(0) + +/* BMR fields */ +#define ATMEL_TC_BMR_TCXC_MSK(c) GENMASK(((c) * 2) + 1, (c) * 2) +#define ATMEL_TC_BMR_TCXC(x, c) ((x) << (2 * (c))) +#define ATMEL_TC_BMR_QDEN BIT(8) +#define ATMEL_TC_BMR_POSEN BIT(9) +#define ATMEL_TC_BMR_SPEEDEN BIT(10) +#define ATMEL_TC_BMR_QDTRANS BIT(11) +#define ATMEL_TC_BMR_EDGPHA BIT(12) +#define ATMEL_TC_BMR_INVA BIT(13) +#define ATMEL_TC_BMR_INVB BIT(14) +#define ATMEL_TC_BMR_INVIDX BIT(15) +#define ATMEL_TC_BMR_SWAP BIT(16) +#define ATMEL_TC_BMR_IDXPHB BIT(17) +#define ATMEL_TC_BMR_AUTOC BIT(18) +#define ATMEL_TC_MAXFILT_MSK GENMASK(25, 20) +#define ATMEL_TC_MAXFILT(x) (((x) - 1) << 20) +#define ATMEL_TC_MAXCMP_MSK GENMASK(29, 26) +#define ATMEL_TC_MAXCMP(x) ((x) << 26) + +/* QEDC fields */ +#define ATMEL_TC_QEDC_IDX BIT(0) +#define ATMEL_TC_QEDC_DIRCHG BIT(1) +#define ATMEL_TC_QEDC_QERR BIT(2) +#define ATMEL_TC_QEDC_MPE BIT(3) +#define ATMEL_TC_QEDC_DIR BIT(8) + +/* FMR fields */ +#define ATMEL_TC_FMR_ENCF(x) BIT(x) + +/* WPMR fields */ +#define ATMEL_TC_WPMR_WPKEY (0x54494d << 8) +#define ATMEL_TC_WPMR_WPEN BIT(0) + +static inline struct clk *tcb_clk_get(struct device_node *node, int channel) +{ + struct clk *clk; + char clk_name[] = "t0_clk"; + + clk_name[1] += channel; + clk = of_clk_get_by_name(node->parent, clk_name); + if (!IS_ERR(clk)) + return clk; + + return of_clk_get_by_name(node->parent, "t0_clk"); +} + +static inline int tcb_irq_get(struct device_node *node, int channel) +{ + int irq; + + irq = of_irq_get(node->parent, channel); + if (irq > 0) + return irq; + + return of_irq_get(node->parent, 0); +} + +static const u8 atmel_tc_divisors[5] = { 2, 8, 32, 128, 0, }; + +struct atmel_tcb_info { + int bits; +}; + +static const struct atmel_tcb_info atmel_tcb_infos[] = { + { .bits = 16 }, + { .bits = 32 }, +}; + +static const struct of_device_id atmel_tcb_dt_ids[] = { + { + .compatible = "atmel,at91rm9200-tcb", + .data = &atmel_tcb_infos[0], + }, { + .compatible = "atmel,at91sam9x5-tcb", + .data = &atmel_tcb_infos[1], + }, { + /* sentinel */ + } +}; + +#endif /* __SOC_ATMEL_TCB_H */ -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 1/6] ARM: at91: add TCB registers definitions 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-07 11:59 ` Philippe Ombredanne -1 siblings, 0 replies; 26+ messages in thread From: Philippe Ombredanne @ 2018-01-07 11:59 UTC (permalink / raw) To: linux-arm-kernel On Fri, Jan 5, 2018 at 3:30 PM, Alexandre Belloni <alexandre.belloni@free-electrons.com> wrote: > Add registers and bits definitions for the timer counter blocks found on > Atmel ARM SoCs. > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > --- > include/soc/at91/atmel_tcb.h | 229 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 229 insertions(+) > create mode 100644 include/soc/at91/atmel_tcb.h > > diff --git a/include/soc/at91/atmel_tcb.h b/include/soc/at91/atmel_tcb.h > new file mode 100644 > index 000000000000..f48e60f8ab92 > --- /dev/null > +++ b/include/soc/at91/atmel_tcb.h > @@ -0,0 +1,229 @@ > +/* > + * Copyright (C) 2016 Atmel > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along with > + * this program. If not, see <http://www.gnu.org/licenses/>. > + */ Alexandre, Would you mind using SPDx tags here like you did in /drivers/clocksource/timer-atmel-tcb.c ? Thanks! -- Cordially Philippe Ombredanne ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 1/6] ARM: at91: add TCB registers definitions @ 2018-01-07 11:59 ` Philippe Ombredanne 0 siblings, 0 replies; 26+ messages in thread From: Philippe Ombredanne @ 2018-01-07 11:59 UTC (permalink / raw) To: Alexandre Belloni Cc: Daniel Lezcano, Thomas Gleixner, Nicolas Ferre, Boris Brezillon, moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE, LKML On Fri, Jan 5, 2018 at 3:30 PM, Alexandre Belloni <alexandre.belloni@free-electrons.com> wrote: > Add registers and bits definitions for the timer counter blocks found on > Atmel ARM SoCs. > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > --- > include/soc/at91/atmel_tcb.h | 229 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 229 insertions(+) > create mode 100644 include/soc/at91/atmel_tcb.h > > diff --git a/include/soc/at91/atmel_tcb.h b/include/soc/at91/atmel_tcb.h > new file mode 100644 > index 000000000000..f48e60f8ab92 > --- /dev/null > +++ b/include/soc/at91/atmel_tcb.h > @@ -0,0 +1,229 @@ > +/* > + * Copyright (C) 2016 Atmel > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, but WITHOUT > + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for > + * more details. > + * > + * You should have received a copy of the GNU General Public License along with > + * this program. If not, see <http://www.gnu.org/licenses/>. > + */ Alexandre, Would you mind using SPDx tags here like you did in /drivers/clocksource/timer-atmel-tcb.c ? Thanks! -- Cordially Philippe Ombredanne ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 2/6] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel Add a driver for the Atmel Timer Counter Blocks. This driver provides a clocksource and two clockevent devices. One of the clockevent device is linked to the clocksource counter and so it will run at the same frequency. This will be used when there is only on TCB channel available for timers. The other clockevent device runs on a separate TCB channel when available. This driver uses regmap and syscon to be able to probe early in the boot and avoid having to switch on the TCB clocksource later. Using regmap also means that unused TCB channels may be used by other drivers (PWM for example). read/writel are still used to access channel specific registers to avoid the performance impact of regmap (mainly locking). Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- drivers/clocksource/Kconfig | 14 + drivers/clocksource/Makefile | 3 +- drivers/clocksource/timer-atmel-tcb.c | 608 ++++++++++++++++++++++++++++++++++ 3 files changed, 624 insertions(+), 1 deletion(-) create mode 100644 drivers/clocksource/timer-atmel-tcb.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c729a88007d0..5609572e0236 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -390,6 +390,20 @@ config ATMEL_ST help Support for the Atmel ST timer. +config ATMEL_ARM_TCB_CLKSRC + bool "TC Block Clocksource" + select REGMAP_MMIO + depends on GENERIC_CLOCKEVENTS + depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5 || COMPILE_TEST + depends on !ATMEL_TCLIB + default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5 + help + Select this to get a high precision clocksource based on a + TC block with a 5+ MHz base clock rate. + On platforms with 16-bit counters, two timer channels are combined + to make a single 32-bit timer. + It can also be used as a clock event device supporting oneshot mode. + config CLKSRC_METAG_GENERIC def_bool y if METAG help diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 72711f1491e3..d3aa71da783b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o -obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o +obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o +obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC) += timer-atmel-tcb.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c new file mode 100644 index 000000000000..7fde9cfbf203 --- /dev/null +++ b/drivers/clocksource/timer-atmel-tcb.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/regmap.h> +#include <linux/sched_clock.h> +#include <soc/at91/atmel_tcb.h> + +static struct atmel_tcb_clksrc { + struct clocksource clksrc; + struct clock_event_device clkevt; + struct regmap *regmap; + void __iomem *base; + struct clk *clk[2]; + char name[20]; + int channels[2]; + int bits; + int irq; + struct { + u32 cmr; + u32 imr; + u32 rc; + bool clken; + } cache[2]; + u32 bmr_cache; + bool registered; +} tc = { + .clksrc = { + .rating = 200, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, + .clkevt = { + .features = CLOCK_EVT_FEAT_ONESHOT, + /* Should be lower than at91rm9200's system timer */ + .rating = 125, + }, +}; + +static struct tc_clkevt_device { + struct clock_event_device clkevt; + struct regmap *regmap; + void __iomem *base; + struct clk *slow_clk; + struct clk *clk; + char name[20]; + int channel; + int irq; + struct { + u32 cmr; + u32 imr; + u32 rc; + bool clken; + } cache; + bool registered; +} tce = { + .clkevt = { + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + /* + * Should be lower than at91rm9200's system timer + * but higher than tc.clkevt.rating + */ + .rating = 140, + }, +}; + +/* + * Clockevent device using its own channel + */ +static int tc_clkevt2_shutdown(struct clock_event_device *d) +{ + writel(0xff, tce.base + ATMEL_TC_IDR(tce.channel)); + writel(ATMEL_TC_CCR_CLKDIS, tce.base + ATMEL_TC_CCR(tce.channel)); + if (!clockevent_state_detached(d)) + clk_disable(tce.clk); + + return 0; +} + +/* For now, we always use the 32K clock ... this optimizes for NO_HZ, + * because using one of the divided clocks would usually mean the + * tick rate can never be less than several dozen Hz (vs 0.5 Hz). + * + * A divided clock could be good for high resolution timers, since + * 30.5 usec resolution can seem "low". + */ +static int tc_clkevt2_set_oneshot(struct clock_event_device *d) +{ + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_clkevt2_shutdown(d); + + clk_enable(tce.clk); + + /* slow clock, count up to RC, then irq and stop */ + writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_CPCSTOP | + ATMEL_TC_CMR_WAVE | ATMEL_TC_CMR_WAVESEL_UPRC, + tce.base + ATMEL_TC_CMR(tce.channel)); + writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channel)); + + return 0; +} + +static int tc_clkevt2_set_periodic(struct clock_event_device *d) +{ + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_clkevt2_shutdown(d); + + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ + clk_enable(tce.clk); + + /* slow clock, count up to RC, then irq and restart */ + writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_WAVE | + ATMEL_TC_CMR_WAVESEL_UPRC, + tce.base + ATMEL_TC_CMR(tce.channel)); + writel((32768 + HZ / 2) / HZ, tce.base + ATMEL_TC_RC(tce.channel)); + + /* Enable clock and interrupts on RC compare */ + writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channel)); + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tce.base + ATMEL_TC_CCR(tce.channel)); + + return 0; +} + +static int tc_clkevt2_next_event(unsigned long delta, + struct clock_event_device *d) +{ + writel(delta, tce.base + ATMEL_TC_RC(tce.channel)); + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tce.base + ATMEL_TC_CCR(tce.channel)); + + return 0; +} + +static irqreturn_t tc_clkevt2_irq(int irq, void *handle) +{ + unsigned int sr; + + sr = readl(tce.base + ATMEL_TC_SR(tce.channel)); + if (sr & ATMEL_TC_CPCS) { + tce.clkevt.event_handler(&tce.clkevt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void tc_clkevt2_suspend(struct clock_event_device *d) +{ + tce.cache.cmr = readl(tce.base + ATMEL_TC_CMR(tce.channel)); + tce.cache.imr = readl(tce.base + ATMEL_TC_IMR(tce.channel)); + tce.cache.rc = readl(tce.base + ATMEL_TC_RC(tce.channel)); + tce.cache.clken = !!(readl(tce.base + ATMEL_TC_SR(tce.channel)) & + ATMEL_TC_CLKSTA); +} + +static void tc_clkevt2_resume(struct clock_event_device *d) +{ + /* Restore registers for the channel, RA and RB are not used */ + writel(tce.cache.cmr, tc.base + ATMEL_TC_CMR(tce.channel)); + writel(tce.cache.rc, tc.base + ATMEL_TC_RC(tce.channel)); + writel(0, tc.base + ATMEL_TC_RA(tce.channel)); + writel(0, tc.base + ATMEL_TC_RB(tce.channel)); + /* Disable all the interrupts */ + writel(0xff, tc.base + ATMEL_TC_IDR(tce.channel)); + /* Reenable interrupts that were enabled before suspending */ + writel(tce.cache.imr, tc.base + ATMEL_TC_IER(tce.channel)); + + /* Start the clock if it was used */ + if (tce.cache.clken) + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tc.base + ATMEL_TC_CCR(tce.channel)); +} + +static int __init tc_clkevt_register(struct device_node *node, + struct regmap *regmap, void __iomem *base, + int channel, int irq, int bits) +{ + int ret; + + tce.regmap = regmap; + tce.base = base; + tce.channel = channel; + tce.irq = irq; + + tce.slow_clk = of_clk_get_by_name(node->parent, "slow_clk"); + if (IS_ERR(tce.slow_clk)) + return PTR_ERR(tce.slow_clk); + + ret = clk_prepare_enable(tce.slow_clk); + if (ret) + return ret; + + tce.clk = tcb_clk_get(node, tce.channel); + if (IS_ERR(tce.clk)) { + ret = PTR_ERR(tce.clk); + goto err_slow; + } + + snprintf(tce.name, sizeof(tce.name), "%s:%d", + kbasename(node->parent->full_name), channel); + tce.clkevt.cpumask = cpumask_of(0); + tce.clkevt.name = tce.name; + tce.clkevt.set_next_event = tc_clkevt2_next_event, + tce.clkevt.set_state_shutdown = tc_clkevt2_shutdown, + tce.clkevt.set_state_periodic = tc_clkevt2_set_periodic, + tce.clkevt.set_state_oneshot = tc_clkevt2_set_oneshot, + tce.clkevt.suspend = tc_clkevt2_suspend, + tce.clkevt.resume = tc_clkevt2_resume, + + /* try to enable clk to avoid future errors in mode change */ + ret = clk_prepare_enable(tce.clk); + if (ret) + goto err_slow; + clk_disable(tce.clk); + + clockevents_config_and_register(&tce.clkevt, 32768, 1, bits - 1); + + ret = request_irq(tce.irq, tc_clkevt2_irq, IRQF_TIMER | IRQF_SHARED, + tce.clkevt.name, &tce); + if (ret) + goto err_clk; + + tce.registered = true; + + return 0; + +err_clk: + clk_unprepare(tce.clk); +err_slow: + clk_disable_unprepare(tce.slow_clk); + + return ret; +} + +/* + * Clocksource and clockevent using the same channel(s) + */ +static u64 tc_get_cycles(struct clocksource *cs) +{ + u32 lower, upper; + + do { + upper = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1])); + lower = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); + } while (upper != readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1]))); + + return (upper << 16) | lower; +} + +static u64 tc_get_cycles32(struct clocksource *cs) +{ + return readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); +} + +static u64 notrace tc_sched_clock_read(void) +{ + return tc_get_cycles(&tc.clksrc); +} + +static u64 notrace tc_sched_clock_read32(void) +{ + return tc_get_cycles32(&tc.clksrc); +} + +static int tcb_clkevt_next_event(unsigned long delta, + struct clock_event_device *d) +{ + u32 old, next, cur; + + + old = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); + next = old + delta; + writel(next, tc.base + ATMEL_TC_RC(tc.channels[0])); + cur = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); + + /* check whether the delta elapsed while setting the register */ + if ((next < old && cur < old && cur > next) || + (next > old && (cur < old || cur > next))) { + /* + * Clear the CPCS bit in the status register to avoid + * generating a spurious interrupt next time a valid + * timer event is configured. + */ + old = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); + return -ETIME; + } + + writel(ATMEL_TC_CPCS, tc.base + ATMEL_TC_IER(tc.channels[0])); + + return 0; +} + +static irqreturn_t tc_clkevt_irq(int irq, void *handle) +{ + unsigned int sr; + + sr = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); + if (sr & ATMEL_TC_CPCS) { + tc.clkevt.event_handler(&tc.clkevt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int tcb_clkevt_oneshot(struct clock_event_device *dev) +{ + if (clockevent_state_oneshot(dev)) + return 0; + + /* + * Because both clockevent devices may share the same IRQ, we don't want + * the less likely one to stay requested + */ + return request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED, + tc.name, &tc); +} + +static int tcb_clkevt_shutdown(struct clock_event_device *dev) +{ + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[0])); + if (tc.bits == 16) + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[1])); + + if (!clockevent_state_detached(dev)) + free_irq(tc.irq, &tc); + + return 0; +} + +static void __init tcb_setup_dual_chan(struct atmel_tcb_clksrc *tc, + int mck_divisor_idx) +{ + /* first channel: waveform mode, input mclk/8, clock TIOA on overflow */ + writel(mck_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP /* free-run */ + | ATMEL_TC_CMR_ACPA(SET) /* TIOA rises at 0 */ + | ATMEL_TC_CMR_ACPC(CLEAR), /* (duty cycle 50%) */ + tc->base + ATMEL_TC_CMR(tc->channels[0])); + writel(0x0000, tc->base + ATMEL_TC_RA(tc->channels[0])); + writel(0x8000, tc->base + ATMEL_TC_RC(tc->channels[0])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); + + /* second channel: waveform mode, input TIOA */ + writel(ATMEL_TC_CMR_XC(tc->channels[1]) /* input: TIOA */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ + tc->base + ATMEL_TC_CMR(tc->channels[1])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[1])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[1])); + + /* chain both channel, we assume the previous channel */ + regmap_write(tc->regmap, ATMEL_TC_BMR, + ATMEL_TC_BMR_TCXC(1 + tc->channels[1], tc->channels[1])); + /* then reset all the timers */ + regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static void __init tcb_setup_single_chan(struct atmel_tcb_clksrc *tc, + int mck_divisor_idx) +{ + /* channel 0: waveform mode, input mclk/8 */ + writel(mck_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ + tc->base + ATMEL_TC_CMR(tc->channels[0])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); + + /* then reset all the timers */ + regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static void tc_clksrc_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < 1 + (tc.bits == 16); i++) { + tc.cache[i].cmr = readl(tc.base + ATMEL_TC_CMR(tc.channels[i])); + tc.cache[i].imr = readl(tc.base + ATMEL_TC_IMR(tc.channels[i])); + tc.cache[i].rc = readl(tc.base + ATMEL_TC_RC(tc.channels[i])); + tc.cache[i].clken = !!(readl(tc.base + + ATMEL_TC_SR(tc.channels[i])) & + ATMEL_TC_CLKSTA); + } + + if (tc.bits == 16) + regmap_read(tc.regmap, ATMEL_TC_BMR, &tc.bmr_cache); +} + +static void tc_clksrc_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < 1 + (tc.bits == 16); i++) { + /* Restore registers for the channel, RA and RB are not used */ + writel(tc.cache[i].cmr, tc.base + ATMEL_TC_CMR(tc.channels[i])); + writel(tc.cache[i].rc, tc.base + ATMEL_TC_RC(tc.channels[i])); + writel(0, tc.base + ATMEL_TC_RA(tc.channels[i])); + writel(0, tc.base + ATMEL_TC_RB(tc.channels[i])); + /* Disable all the interrupts */ + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[i])); + /* Reenable interrupts that were enabled before suspending */ + writel(tc.cache[i].imr, tc.base + ATMEL_TC_IER(tc.channels[i])); + + /* Start the clock if it was used */ + if (tc.cache[i].clken) + writel(ATMEL_TC_CCR_CLKEN, tc.base + + ATMEL_TC_CCR(tc.channels[i])); + } + + /* in case of dual channel, chain channels */ + if (tc.bits == 16) + regmap_write(tc.regmap, ATMEL_TC_BMR, tc.bmr_cache); + /* Finally, trigger all the channels*/ + regmap_write(tc.regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static int __init tcb_clksrc_register(struct device_node *node, + struct regmap *regmap, void __iomem *base, + int channel, int channel1, int irq, + int bits) +{ + u32 rate, divided_rate = 0; + int best_divisor_idx = -1; + int i, err = -1; + u64 (*tc_sched_clock)(void); + + tc.regmap = regmap; + tc.base = base; + tc.channels[0] = channel; + tc.channels[1] = channel1; + tc.irq = irq; + tc.bits = bits; + + tc.clk[0] = tcb_clk_get(node, tc.channels[0]); + if (IS_ERR(tc.clk[0])) + return PTR_ERR(tc.clk[0]); + err = clk_prepare_enable(tc.clk[0]); + if (err) { + pr_debug("can't enable T0 clk\n"); + goto err_clk; + } + + /* How fast will we be counting? Pick something over 5 MHz. */ + rate = (u32)clk_get_rate(tc.clk[0]); + for (i = 0; i < 5; i++) { + unsigned int divisor = atmel_tc_divisors[i]; + unsigned int tmp; + + if (!divisor) + continue; + + tmp = rate / divisor; + pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp); + if (best_divisor_idx > 0) { + if (tmp < 5 * 1000 * 1000) + continue; + } + divided_rate = tmp; + best_divisor_idx = i; + } + + if (tc.bits == 32) { + tc.clksrc.read = tc_get_cycles32; + tcb_setup_single_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read32; + snprintf(tc.name, sizeof(tc.name), "%s:%d", + kbasename(node->parent->full_name), tc.channels[0]); + } else { + tc.clk[1] = tcb_clk_get(node, tc.channels[1]); + if (IS_ERR(tc.clk[1])) + goto err_disable_t0; + + err = clk_prepare_enable(tc.clk[1]); + if (err) { + pr_debug("can't enable T1 clk\n"); + goto err_clk1; + } + tc.clksrc.read = tc_get_cycles, + tcb_setup_dual_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read; + snprintf(tc.name, sizeof(tc.name), "%s:%d,%d", + kbasename(node->parent->full_name), tc.channels[0], + tc.channels[1]); + } + + pr_debug("%s at %d.%03d MHz\n", tc.name, + divided_rate / 1000000, + ((divided_rate + 500000) % 1000000) / 1000); + + tc.clksrc.name = tc.name; + tc.clksrc.suspend = tc_clksrc_suspend; + tc.clksrc.resume = tc_clksrc_resume; + + err = clocksource_register_hz(&tc.clksrc, divided_rate); + if (err) + goto err_disable_t1; + + sched_clock_register(tc_sched_clock, 32, divided_rate); + + tc.registered = true; + + /* Set up and register clockevents */ + tc.clkevt.name = tc.name; + tc.clkevt.cpumask = cpumask_of(0); + tc.clkevt.set_next_event = tcb_clkevt_next_event; + tc.clkevt.set_state_oneshot = tcb_clkevt_oneshot; + tc.clkevt.set_state_shutdown = tcb_clkevt_shutdown; + clockevents_config_and_register(&tc.clkevt, divided_rate, 1, + BIT(tc.bits) - 1); + + return 0; + +err_disable_t1: + if (tc.bits == 16) + clk_disable_unprepare(tc.clk[1]); + +err_clk1: + if (tc.bits == 16) + clk_put(tc.clk[1]); + +err_disable_t0: + clk_disable_unprepare(tc.clk[0]); + +err_clk: + clk_put(tc.clk[0]); + + pr_err("%s: unable to register clocksource/clockevent\n", + tc.clksrc.name); + + return err; +} + +static int __init tcb_clksrc_init(struct device_node *node) +{ + const struct of_device_id *match; + const struct atmel_tcb_info *tcb_info; + struct regmap *regmap; + void __iomem *tcb_base; + u32 channel; + int bits, irq, err, chan1 = -1; + + if (tc.registered && tce.registered) + return -ENODEV; + + /* + * The regmap has to be used to access registers that are shared + * between channels on the same TCB but we keep direct IO access for + * the counters to avoid the impact on performance + */ + regmap = syscon_node_to_regmap(node->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + tcb_base = of_iomap(node->parent, 0); + if (!tcb_base) { + pr_err("%s +%d %s\n", __FILE__, __LINE__, __func__); + return -ENXIO; + } + + match = of_match_node(atmel_tcb_dt_ids, node->parent); + tcb_info = match->data; + bits = tcb_info->bits; + + err = of_property_read_u32_index(node, "reg", 0, &channel); + if (err) + return err; + + irq = tcb_irq_get(node, channel); + if (irq < 0) + return irq; + + if (tc.registered) + return tc_clkevt_register(node, regmap, tcb_base, channel, irq, + bits); + + if (bits == 16) { + of_property_read_u32_index(node, "reg", 1, &chan1); + if (chan1 == -1) { + if (tce.registered) { + pr_err("%s: clocksource needs two channels\n", + node->parent->full_name); + return -EINVAL; + } else { + return tc_clkevt_register(node, regmap, + tcb_base, channel, + irq, bits); + } + } + } + + return tcb_clksrc_register(node, regmap, tcb_base, channel, chan1, irq, + bits); +} +CLOCKSOURCE_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", + tcb_clksrc_init); -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 2/6] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni Add a driver for the Atmel Timer Counter Blocks. This driver provides a clocksource and two clockevent devices. One of the clockevent device is linked to the clocksource counter and so it will run at the same frequency. This will be used when there is only on TCB channel available for timers. The other clockevent device runs on a separate TCB channel when available. This driver uses regmap and syscon to be able to probe early in the boot and avoid having to switch on the TCB clocksource later. Using regmap also means that unused TCB channels may be used by other drivers (PWM for example). read/writel are still used to access channel specific registers to avoid the performance impact of regmap (mainly locking). Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- drivers/clocksource/Kconfig | 14 + drivers/clocksource/Makefile | 3 +- drivers/clocksource/timer-atmel-tcb.c | 608 ++++++++++++++++++++++++++++++++++ 3 files changed, 624 insertions(+), 1 deletion(-) create mode 100644 drivers/clocksource/timer-atmel-tcb.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index c729a88007d0..5609572e0236 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -390,6 +390,20 @@ config ATMEL_ST help Support for the Atmel ST timer. +config ATMEL_ARM_TCB_CLKSRC + bool "TC Block Clocksource" + select REGMAP_MMIO + depends on GENERIC_CLOCKEVENTS + depends on SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5 || COMPILE_TEST + depends on !ATMEL_TCLIB + default SOC_AT91RM9200 || SOC_AT91SAM9 || SOC_SAMA5 + help + Select this to get a high precision clocksource based on a + TC block with a 5+ MHz base clock rate. + On platforms with 16-bit counters, two timer channels are combined + to make a single 32-bit timer. + It can also be used as a clock event device supporting oneshot mode. + config CLKSRC_METAG_GENERIC def_bool y if METAG help diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 72711f1491e3..d3aa71da783b 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_TIMER_OF) += timer-of.o obj-$(CONFIG_TIMER_PROBE) += timer-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o -obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o +obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o +obj-$(CONFIG_ATMEL_ARM_TCB_CLKSRC) += timer-atmel-tcb.o obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o diff --git a/drivers/clocksource/timer-atmel-tcb.c b/drivers/clocksource/timer-atmel-tcb.c new file mode 100644 index 000000000000..7fde9cfbf203 --- /dev/null +++ b/drivers/clocksource/timer-atmel-tcb.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/regmap.h> +#include <linux/sched_clock.h> +#include <soc/at91/atmel_tcb.h> + +static struct atmel_tcb_clksrc { + struct clocksource clksrc; + struct clock_event_device clkevt; + struct regmap *regmap; + void __iomem *base; + struct clk *clk[2]; + char name[20]; + int channels[2]; + int bits; + int irq; + struct { + u32 cmr; + u32 imr; + u32 rc; + bool clken; + } cache[2]; + u32 bmr_cache; + bool registered; +} tc = { + .clksrc = { + .rating = 200, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }, + .clkevt = { + .features = CLOCK_EVT_FEAT_ONESHOT, + /* Should be lower than at91rm9200's system timer */ + .rating = 125, + }, +}; + +static struct tc_clkevt_device { + struct clock_event_device clkevt; + struct regmap *regmap; + void __iomem *base; + struct clk *slow_clk; + struct clk *clk; + char name[20]; + int channel; + int irq; + struct { + u32 cmr; + u32 imr; + u32 rc; + bool clken; + } cache; + bool registered; +} tce = { + .clkevt = { + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + /* + * Should be lower than at91rm9200's system timer + * but higher than tc.clkevt.rating + */ + .rating = 140, + }, +}; + +/* + * Clockevent device using its own channel + */ +static int tc_clkevt2_shutdown(struct clock_event_device *d) +{ + writel(0xff, tce.base + ATMEL_TC_IDR(tce.channel)); + writel(ATMEL_TC_CCR_CLKDIS, tce.base + ATMEL_TC_CCR(tce.channel)); + if (!clockevent_state_detached(d)) + clk_disable(tce.clk); + + return 0; +} + +/* For now, we always use the 32K clock ... this optimizes for NO_HZ, + * because using one of the divided clocks would usually mean the + * tick rate can never be less than several dozen Hz (vs 0.5 Hz). + * + * A divided clock could be good for high resolution timers, since + * 30.5 usec resolution can seem "low". + */ +static int tc_clkevt2_set_oneshot(struct clock_event_device *d) +{ + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_clkevt2_shutdown(d); + + clk_enable(tce.clk); + + /* slow clock, count up to RC, then irq and stop */ + writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_CPCSTOP | + ATMEL_TC_CMR_WAVE | ATMEL_TC_CMR_WAVESEL_UPRC, + tce.base + ATMEL_TC_CMR(tce.channel)); + writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channel)); + + return 0; +} + +static int tc_clkevt2_set_periodic(struct clock_event_device *d) +{ + if (clockevent_state_oneshot(d) || clockevent_state_periodic(d)) + tc_clkevt2_shutdown(d); + + /* By not making the gentime core emulate periodic mode on top + * of oneshot, we get lower overhead and improved accuracy. + */ + clk_enable(tce.clk); + + /* slow clock, count up to RC, then irq and restart */ + writel(ATMEL_TC_CMR_TCLK(4) | ATMEL_TC_CMR_WAVE | + ATMEL_TC_CMR_WAVESEL_UPRC, + tce.base + ATMEL_TC_CMR(tce.channel)); + writel((32768 + HZ / 2) / HZ, tce.base + ATMEL_TC_RC(tce.channel)); + + /* Enable clock and interrupts on RC compare */ + writel(ATMEL_TC_CPCS, tce.base + ATMEL_TC_IER(tce.channel)); + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tce.base + ATMEL_TC_CCR(tce.channel)); + + return 0; +} + +static int tc_clkevt2_next_event(unsigned long delta, + struct clock_event_device *d) +{ + writel(delta, tce.base + ATMEL_TC_RC(tce.channel)); + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tce.base + ATMEL_TC_CCR(tce.channel)); + + return 0; +} + +static irqreturn_t tc_clkevt2_irq(int irq, void *handle) +{ + unsigned int sr; + + sr = readl(tce.base + ATMEL_TC_SR(tce.channel)); + if (sr & ATMEL_TC_CPCS) { + tce.clkevt.event_handler(&tce.clkevt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static void tc_clkevt2_suspend(struct clock_event_device *d) +{ + tce.cache.cmr = readl(tce.base + ATMEL_TC_CMR(tce.channel)); + tce.cache.imr = readl(tce.base + ATMEL_TC_IMR(tce.channel)); + tce.cache.rc = readl(tce.base + ATMEL_TC_RC(tce.channel)); + tce.cache.clken = !!(readl(tce.base + ATMEL_TC_SR(tce.channel)) & + ATMEL_TC_CLKSTA); +} + +static void tc_clkevt2_resume(struct clock_event_device *d) +{ + /* Restore registers for the channel, RA and RB are not used */ + writel(tce.cache.cmr, tc.base + ATMEL_TC_CMR(tce.channel)); + writel(tce.cache.rc, tc.base + ATMEL_TC_RC(tce.channel)); + writel(0, tc.base + ATMEL_TC_RA(tce.channel)); + writel(0, tc.base + ATMEL_TC_RB(tce.channel)); + /* Disable all the interrupts */ + writel(0xff, tc.base + ATMEL_TC_IDR(tce.channel)); + /* Reenable interrupts that were enabled before suspending */ + writel(tce.cache.imr, tc.base + ATMEL_TC_IER(tce.channel)); + + /* Start the clock if it was used */ + if (tce.cache.clken) + writel(ATMEL_TC_CCR_CLKEN | ATMEL_TC_CCR_SWTRG, + tc.base + ATMEL_TC_CCR(tce.channel)); +} + +static int __init tc_clkevt_register(struct device_node *node, + struct regmap *regmap, void __iomem *base, + int channel, int irq, int bits) +{ + int ret; + + tce.regmap = regmap; + tce.base = base; + tce.channel = channel; + tce.irq = irq; + + tce.slow_clk = of_clk_get_by_name(node->parent, "slow_clk"); + if (IS_ERR(tce.slow_clk)) + return PTR_ERR(tce.slow_clk); + + ret = clk_prepare_enable(tce.slow_clk); + if (ret) + return ret; + + tce.clk = tcb_clk_get(node, tce.channel); + if (IS_ERR(tce.clk)) { + ret = PTR_ERR(tce.clk); + goto err_slow; + } + + snprintf(tce.name, sizeof(tce.name), "%s:%d", + kbasename(node->parent->full_name), channel); + tce.clkevt.cpumask = cpumask_of(0); + tce.clkevt.name = tce.name; + tce.clkevt.set_next_event = tc_clkevt2_next_event, + tce.clkevt.set_state_shutdown = tc_clkevt2_shutdown, + tce.clkevt.set_state_periodic = tc_clkevt2_set_periodic, + tce.clkevt.set_state_oneshot = tc_clkevt2_set_oneshot, + tce.clkevt.suspend = tc_clkevt2_suspend, + tce.clkevt.resume = tc_clkevt2_resume, + + /* try to enable clk to avoid future errors in mode change */ + ret = clk_prepare_enable(tce.clk); + if (ret) + goto err_slow; + clk_disable(tce.clk); + + clockevents_config_and_register(&tce.clkevt, 32768, 1, bits - 1); + + ret = request_irq(tce.irq, tc_clkevt2_irq, IRQF_TIMER | IRQF_SHARED, + tce.clkevt.name, &tce); + if (ret) + goto err_clk; + + tce.registered = true; + + return 0; + +err_clk: + clk_unprepare(tce.clk); +err_slow: + clk_disable_unprepare(tce.slow_clk); + + return ret; +} + +/* + * Clocksource and clockevent using the same channel(s) + */ +static u64 tc_get_cycles(struct clocksource *cs) +{ + u32 lower, upper; + + do { + upper = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1])); + lower = readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); + } while (upper != readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[1]))); + + return (upper << 16) | lower; +} + +static u64 tc_get_cycles32(struct clocksource *cs) +{ + return readl_relaxed(tc.base + ATMEL_TC_CV(tc.channels[0])); +} + +static u64 notrace tc_sched_clock_read(void) +{ + return tc_get_cycles(&tc.clksrc); +} + +static u64 notrace tc_sched_clock_read32(void) +{ + return tc_get_cycles32(&tc.clksrc); +} + +static int tcb_clkevt_next_event(unsigned long delta, + struct clock_event_device *d) +{ + u32 old, next, cur; + + + old = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); + next = old + delta; + writel(next, tc.base + ATMEL_TC_RC(tc.channels[0])); + cur = readl(tc.base + ATMEL_TC_CV(tc.channels[0])); + + /* check whether the delta elapsed while setting the register */ + if ((next < old && cur < old && cur > next) || + (next > old && (cur < old || cur > next))) { + /* + * Clear the CPCS bit in the status register to avoid + * generating a spurious interrupt next time a valid + * timer event is configured. + */ + old = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); + return -ETIME; + } + + writel(ATMEL_TC_CPCS, tc.base + ATMEL_TC_IER(tc.channels[0])); + + return 0; +} + +static irqreturn_t tc_clkevt_irq(int irq, void *handle) +{ + unsigned int sr; + + sr = readl(tc.base + ATMEL_TC_SR(tc.channels[0])); + if (sr & ATMEL_TC_CPCS) { + tc.clkevt.event_handler(&tc.clkevt); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int tcb_clkevt_oneshot(struct clock_event_device *dev) +{ + if (clockevent_state_oneshot(dev)) + return 0; + + /* + * Because both clockevent devices may share the same IRQ, we don't want + * the less likely one to stay requested + */ + return request_irq(tc.irq, tc_clkevt_irq, IRQF_TIMER | IRQF_SHARED, + tc.name, &tc); +} + +static int tcb_clkevt_shutdown(struct clock_event_device *dev) +{ + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[0])); + if (tc.bits == 16) + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[1])); + + if (!clockevent_state_detached(dev)) + free_irq(tc.irq, &tc); + + return 0; +} + +static void __init tcb_setup_dual_chan(struct atmel_tcb_clksrc *tc, + int mck_divisor_idx) +{ + /* first channel: waveform mode, input mclk/8, clock TIOA on overflow */ + writel(mck_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP /* free-run */ + | ATMEL_TC_CMR_ACPA(SET) /* TIOA rises at 0 */ + | ATMEL_TC_CMR_ACPC(CLEAR), /* (duty cycle 50%) */ + tc->base + ATMEL_TC_CMR(tc->channels[0])); + writel(0x0000, tc->base + ATMEL_TC_RA(tc->channels[0])); + writel(0x8000, tc->base + ATMEL_TC_RC(tc->channels[0])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); + + /* second channel: waveform mode, input TIOA */ + writel(ATMEL_TC_CMR_XC(tc->channels[1]) /* input: TIOA */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ + tc->base + ATMEL_TC_CMR(tc->channels[1])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[1])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[1])); + + /* chain both channel, we assume the previous channel */ + regmap_write(tc->regmap, ATMEL_TC_BMR, + ATMEL_TC_BMR_TCXC(1 + tc->channels[1], tc->channels[1])); + /* then reset all the timers */ + regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static void __init tcb_setup_single_chan(struct atmel_tcb_clksrc *tc, + int mck_divisor_idx) +{ + /* channel 0: waveform mode, input mclk/8 */ + writel(mck_divisor_idx /* likely divide-by-8 */ + | ATMEL_TC_CMR_WAVE + | ATMEL_TC_CMR_WAVESEL_UP, /* free-run */ + tc->base + ATMEL_TC_CMR(tc->channels[0])); + writel(0xff, tc->base + ATMEL_TC_IDR(tc->channels[0])); /* no irqs */ + writel(ATMEL_TC_CCR_CLKEN, tc->base + ATMEL_TC_CCR(tc->channels[0])); + + /* then reset all the timers */ + regmap_write(tc->regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static void tc_clksrc_suspend(struct clocksource *cs) +{ + int i; + + for (i = 0; i < 1 + (tc.bits == 16); i++) { + tc.cache[i].cmr = readl(tc.base + ATMEL_TC_CMR(tc.channels[i])); + tc.cache[i].imr = readl(tc.base + ATMEL_TC_IMR(tc.channels[i])); + tc.cache[i].rc = readl(tc.base + ATMEL_TC_RC(tc.channels[i])); + tc.cache[i].clken = !!(readl(tc.base + + ATMEL_TC_SR(tc.channels[i])) & + ATMEL_TC_CLKSTA); + } + + if (tc.bits == 16) + regmap_read(tc.regmap, ATMEL_TC_BMR, &tc.bmr_cache); +} + +static void tc_clksrc_resume(struct clocksource *cs) +{ + int i; + + for (i = 0; i < 1 + (tc.bits == 16); i++) { + /* Restore registers for the channel, RA and RB are not used */ + writel(tc.cache[i].cmr, tc.base + ATMEL_TC_CMR(tc.channels[i])); + writel(tc.cache[i].rc, tc.base + ATMEL_TC_RC(tc.channels[i])); + writel(0, tc.base + ATMEL_TC_RA(tc.channels[i])); + writel(0, tc.base + ATMEL_TC_RB(tc.channels[i])); + /* Disable all the interrupts */ + writel(0xff, tc.base + ATMEL_TC_IDR(tc.channels[i])); + /* Reenable interrupts that were enabled before suspending */ + writel(tc.cache[i].imr, tc.base + ATMEL_TC_IER(tc.channels[i])); + + /* Start the clock if it was used */ + if (tc.cache[i].clken) + writel(ATMEL_TC_CCR_CLKEN, tc.base + + ATMEL_TC_CCR(tc.channels[i])); + } + + /* in case of dual channel, chain channels */ + if (tc.bits == 16) + regmap_write(tc.regmap, ATMEL_TC_BMR, tc.bmr_cache); + /* Finally, trigger all the channels*/ + regmap_write(tc.regmap, ATMEL_TC_BCR, ATMEL_TC_BCR_SYNC); +} + +static int __init tcb_clksrc_register(struct device_node *node, + struct regmap *regmap, void __iomem *base, + int channel, int channel1, int irq, + int bits) +{ + u32 rate, divided_rate = 0; + int best_divisor_idx = -1; + int i, err = -1; + u64 (*tc_sched_clock)(void); + + tc.regmap = regmap; + tc.base = base; + tc.channels[0] = channel; + tc.channels[1] = channel1; + tc.irq = irq; + tc.bits = bits; + + tc.clk[0] = tcb_clk_get(node, tc.channels[0]); + if (IS_ERR(tc.clk[0])) + return PTR_ERR(tc.clk[0]); + err = clk_prepare_enable(tc.clk[0]); + if (err) { + pr_debug("can't enable T0 clk\n"); + goto err_clk; + } + + /* How fast will we be counting? Pick something over 5 MHz. */ + rate = (u32)clk_get_rate(tc.clk[0]); + for (i = 0; i < 5; i++) { + unsigned int divisor = atmel_tc_divisors[i]; + unsigned int tmp; + + if (!divisor) + continue; + + tmp = rate / divisor; + pr_debug("TC: %u / %-3u [%d] --> %u\n", rate, divisor, i, tmp); + if (best_divisor_idx > 0) { + if (tmp < 5 * 1000 * 1000) + continue; + } + divided_rate = tmp; + best_divisor_idx = i; + } + + if (tc.bits == 32) { + tc.clksrc.read = tc_get_cycles32; + tcb_setup_single_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read32; + snprintf(tc.name, sizeof(tc.name), "%s:%d", + kbasename(node->parent->full_name), tc.channels[0]); + } else { + tc.clk[1] = tcb_clk_get(node, tc.channels[1]); + if (IS_ERR(tc.clk[1])) + goto err_disable_t0; + + err = clk_prepare_enable(tc.clk[1]); + if (err) { + pr_debug("can't enable T1 clk\n"); + goto err_clk1; + } + tc.clksrc.read = tc_get_cycles, + tcb_setup_dual_chan(&tc, best_divisor_idx); + tc_sched_clock = tc_sched_clock_read; + snprintf(tc.name, sizeof(tc.name), "%s:%d,%d", + kbasename(node->parent->full_name), tc.channels[0], + tc.channels[1]); + } + + pr_debug("%s at %d.%03d MHz\n", tc.name, + divided_rate / 1000000, + ((divided_rate + 500000) % 1000000) / 1000); + + tc.clksrc.name = tc.name; + tc.clksrc.suspend = tc_clksrc_suspend; + tc.clksrc.resume = tc_clksrc_resume; + + err = clocksource_register_hz(&tc.clksrc, divided_rate); + if (err) + goto err_disable_t1; + + sched_clock_register(tc_sched_clock, 32, divided_rate); + + tc.registered = true; + + /* Set up and register clockevents */ + tc.clkevt.name = tc.name; + tc.clkevt.cpumask = cpumask_of(0); + tc.clkevt.set_next_event = tcb_clkevt_next_event; + tc.clkevt.set_state_oneshot = tcb_clkevt_oneshot; + tc.clkevt.set_state_shutdown = tcb_clkevt_shutdown; + clockevents_config_and_register(&tc.clkevt, divided_rate, 1, + BIT(tc.bits) - 1); + + return 0; + +err_disable_t1: + if (tc.bits == 16) + clk_disable_unprepare(tc.clk[1]); + +err_clk1: + if (tc.bits == 16) + clk_put(tc.clk[1]); + +err_disable_t0: + clk_disable_unprepare(tc.clk[0]); + +err_clk: + clk_put(tc.clk[0]); + + pr_err("%s: unable to register clocksource/clockevent\n", + tc.clksrc.name); + + return err; +} + +static int __init tcb_clksrc_init(struct device_node *node) +{ + const struct of_device_id *match; + const struct atmel_tcb_info *tcb_info; + struct regmap *regmap; + void __iomem *tcb_base; + u32 channel; + int bits, irq, err, chan1 = -1; + + if (tc.registered && tce.registered) + return -ENODEV; + + /* + * The regmap has to be used to access registers that are shared + * between channels on the same TCB but we keep direct IO access for + * the counters to avoid the impact on performance + */ + regmap = syscon_node_to_regmap(node->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + tcb_base = of_iomap(node->parent, 0); + if (!tcb_base) { + pr_err("%s +%d %s\n", __FILE__, __LINE__, __func__); + return -ENXIO; + } + + match = of_match_node(atmel_tcb_dt_ids, node->parent); + tcb_info = match->data; + bits = tcb_info->bits; + + err = of_property_read_u32_index(node, "reg", 0, &channel); + if (err) + return err; + + irq = tcb_irq_get(node, channel); + if (irq < 0) + return irq; + + if (tc.registered) + return tc_clkevt_register(node, regmap, tcb_base, channel, irq, + bits); + + if (bits == 16) { + of_property_read_u32_index(node, "reg", 1, &chan1); + if (chan1 == -1) { + if (tce.registered) { + pr_err("%s: clocksource needs two channels\n", + node->parent->full_name); + return -EINVAL; + } else { + return tc_clkevt_register(node, regmap, + tcb_base, channel, + irq, bits); + } + } + } + + return tcb_clksrc_register(node, regmap, tcb_base, channel, chan1, irq, + bits); +} +CLOCKSOURCE_OF_DECLARE(atmel_tcb_clksrc, "atmel,tcb-timer", + tcb_clksrc_init); -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel With the new TCB clocksource driver, atmel platforms are now able to boot without the PIT driver. Allow unselecting it. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- drivers/clocksource/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5609572e0236..55ccfa0ba63b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK config ATMEL_PIT select TIMER_OF if OF - def_bool SOC_AT91SAM9 || SOC_SAMA5 + bool "Atmel Periodic Interval Timer (PIT)" + depends on SOC_AT91SAM9 || SOC_SAMA5 + default SOC_AT91SAM9 || SOC_SAMA5 + help + Select this to get a clocksource based on the Atmel Periodic Interval + Timer. It has a relatively low resolution and the TC Block clocksource + should be preferred. + It also provides a clock event device. config ATMEL_ST bool "Atmel ST timer support" if COMPILE_TEST -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni With the new TCB clocksource driver, atmel platforms are now able to boot without the PIT driver. Allow unselecting it. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- drivers/clocksource/Kconfig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5609572e0236..55ccfa0ba63b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK config ATMEL_PIT select TIMER_OF if OF - def_bool SOC_AT91SAM9 || SOC_SAMA5 + bool "Atmel Periodic Interval Timer (PIT)" + depends on SOC_AT91SAM9 || SOC_SAMA5 + default SOC_AT91SAM9 || SOC_SAMA5 + help + Select this to get a clocksource based on the Atmel Periodic Interval + Timer. It has a relatively low resolution and the TC Block clocksource + should be preferred. + It also provides a clock event device. config ATMEL_ST bool "Atmel ST timer support" if COMPILE_TEST -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-07 18:07 ` Daniel Lezcano -1 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-07 18:07 UTC (permalink / raw) To: linux-arm-kernel On 05/01/2018 15:30, Alexandre Belloni wrote: > With the new TCB clocksource driver, atmel platforms are now able to boot > without the PIT driver. Allow unselecting it. > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > --- > drivers/clocksource/Kconfig | 9 ++++++++- > 1 file changed, 8 insertions(+), 1 deletion(-) > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > index 5609572e0236..55ccfa0ba63b 100644 > --- a/drivers/clocksource/Kconfig > +++ b/drivers/clocksource/Kconfig > @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > > config ATMEL_PIT > select TIMER_OF if OF > - def_bool SOC_AT91SAM9 || SOC_SAMA5 > + bool "Atmel Periodic Interval Timer (PIT)" > + depends on SOC_AT91SAM9 || SOC_SAMA5 > + default SOC_AT91SAM9 || SOC_SAMA5 > + help > + Select this to get a clocksource based on the Atmel Periodic Interval > + Timer. It has a relatively low resolution and the TC Block clocksource > + should be preferred. > + It also provides a clock event device. Please conform to the format: config ATMEL_PIT bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST select ... help bla bla and select ATMEL_PIT from the platform's Kconfig. > config ATMEL_ST > bool "Atmel ST timer support" if COMPILE_TEST > -- <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-07 18:07 ` Daniel Lezcano 0 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-07 18:07 UTC (permalink / raw) To: Alexandre Belloni Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel On 05/01/2018 15:30, Alexandre Belloni wrote: > With the new TCB clocksource driver, atmel platforms are now able to boot > without the PIT driver. Allow unselecting it. > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > --- > drivers/clocksource/Kconfig | 9 ++++++++- > 1 file changed, 8 insertions(+), 1 deletion(-) > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > index 5609572e0236..55ccfa0ba63b 100644 > --- a/drivers/clocksource/Kconfig > +++ b/drivers/clocksource/Kconfig > @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > > config ATMEL_PIT > select TIMER_OF if OF > - def_bool SOC_AT91SAM9 || SOC_SAMA5 > + bool "Atmel Periodic Interval Timer (PIT)" > + depends on SOC_AT91SAM9 || SOC_SAMA5 > + default SOC_AT91SAM9 || SOC_SAMA5 > + help > + Select this to get a clocksource based on the Atmel Periodic Interval > + Timer. It has a relatively low resolution and the TC Block clocksource > + should be preferred. > + It also provides a clock event device. Please conform to the format: config ATMEL_PIT bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST select ... help bla bla and select ATMEL_PIT from the platform's Kconfig. > config ATMEL_ST > bool "Atmel ST timer support" if COMPILE_TEST > -- <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-07 18:07 ` Daniel Lezcano @ 2018-01-07 18:44 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-07 18:44 UTC (permalink / raw) To: linux-arm-kernel On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: > On 05/01/2018 15:30, Alexandre Belloni wrote: > > With the new TCB clocksource driver, atmel platforms are now able to boot > > without the PIT driver. Allow unselecting it. > > > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > > --- > > drivers/clocksource/Kconfig | 9 ++++++++- > > 1 file changed, 8 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > > index 5609572e0236..55ccfa0ba63b 100644 > > --- a/drivers/clocksource/Kconfig > > +++ b/drivers/clocksource/Kconfig > > @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > > > > config ATMEL_PIT > > select TIMER_OF if OF > > - def_bool SOC_AT91SAM9 || SOC_SAMA5 > > + bool "Atmel Periodic Interval Timer (PIT)" > > + depends on SOC_AT91SAM9 || SOC_SAMA5 > > + default SOC_AT91SAM9 || SOC_SAMA5 > > + help > > + Select this to get a clocksource based on the Atmel Periodic Interval > > + Timer. It has a relatively low resolution and the TC Block clocksource > > + should be preferred. > > + It also provides a clock event device. > > Please conform to the format: > > config ATMEL_PIT > bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST > select ... > help > bla bla > > and select ATMEL_PIT from the platform's Kconfig. > Well, the goal is actually to allow people to unselect it so we don't want the platform to select it. -- Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-07 18:44 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-07 18:44 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: > On 05/01/2018 15:30, Alexandre Belloni wrote: > > With the new TCB clocksource driver, atmel platforms are now able to boot > > without the PIT driver. Allow unselecting it. > > > > Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > > --- > > drivers/clocksource/Kconfig | 9 ++++++++- > > 1 file changed, 8 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > > index 5609572e0236..55ccfa0ba63b 100644 > > --- a/drivers/clocksource/Kconfig > > +++ b/drivers/clocksource/Kconfig > > @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > > > > config ATMEL_PIT > > select TIMER_OF if OF > > - def_bool SOC_AT91SAM9 || SOC_SAMA5 > > + bool "Atmel Periodic Interval Timer (PIT)" > > + depends on SOC_AT91SAM9 || SOC_SAMA5 > > + default SOC_AT91SAM9 || SOC_SAMA5 > > + help > > + Select this to get a clocksource based on the Atmel Periodic Interval > > + Timer. It has a relatively low resolution and the TC Block clocksource > > + should be preferred. > > + It also provides a clock event device. > > Please conform to the format: > > config ATMEL_PIT > bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST > select ... > help > bla bla > > and select ATMEL_PIT from the platform's Kconfig. > Well, the goal is actually to allow people to unselect it so we don't want the platform to select it. -- Alexandre Belloni, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-07 18:44 ` Alexandre Belloni @ 2018-01-08 7:23 ` Daniel Lezcano -1 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-08 7:23 UTC (permalink / raw) To: linux-arm-kernel On 07/01/2018 19:44, Alexandre Belloni wrote: > On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: >> On 05/01/2018 15:30, Alexandre Belloni wrote: >>> With the new TCB clocksource driver, atmel platforms are now able to boot >>> without the PIT driver. Allow unselecting it. >>> >>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> >>> --- >>> drivers/clocksource/Kconfig | 9 ++++++++- >>> 1 file changed, 8 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig >>> index 5609572e0236..55ccfa0ba63b 100644 >>> --- a/drivers/clocksource/Kconfig >>> +++ b/drivers/clocksource/Kconfig >>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK >>> >>> config ATMEL_PIT >>> select TIMER_OF if OF >>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 >>> + bool "Atmel Periodic Interval Timer (PIT)" >>> + depends on SOC_AT91SAM9 || SOC_SAMA5 >>> + default SOC_AT91SAM9 || SOC_SAMA5 >>> + help >>> + Select this to get a clocksource based on the Atmel Periodic Interval >>> + Timer. It has a relatively low resolution and the TC Block clocksource >>> + should be preferred. >>> + It also provides a clock event device. >> >> Please conform to the format: >> >> config ATMEL_PIT >> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST >> select ... >> help >> bla bla >> >> and select ATMEL_PIT from the platform's Kconfig. >> > > Well, the goal is actually to allow people to unselect it so we don't > want the platform to select it. Why do you need people to unselect it? The goal of the Kconfig here is to be silent except in the case the COMPILE_TEST option is set for cross-compilation test coverage. We are migrating all these options to this format. Please make it silent. -- <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-08 7:23 ` Daniel Lezcano 0 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-08 7:23 UTC (permalink / raw) To: Alexandre Belloni Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel On 07/01/2018 19:44, Alexandre Belloni wrote: > On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: >> On 05/01/2018 15:30, Alexandre Belloni wrote: >>> With the new TCB clocksource driver, atmel platforms are now able to boot >>> without the PIT driver. Allow unselecting it. >>> >>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> >>> --- >>> drivers/clocksource/Kconfig | 9 ++++++++- >>> 1 file changed, 8 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig >>> index 5609572e0236..55ccfa0ba63b 100644 >>> --- a/drivers/clocksource/Kconfig >>> +++ b/drivers/clocksource/Kconfig >>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK >>> >>> config ATMEL_PIT >>> select TIMER_OF if OF >>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 >>> + bool "Atmel Periodic Interval Timer (PIT)" >>> + depends on SOC_AT91SAM9 || SOC_SAMA5 >>> + default SOC_AT91SAM9 || SOC_SAMA5 >>> + help >>> + Select this to get a clocksource based on the Atmel Periodic Interval >>> + Timer. It has a relatively low resolution and the TC Block clocksource >>> + should be preferred. >>> + It also provides a clock event device. >> >> Please conform to the format: >> >> config ATMEL_PIT >> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST >> select ... >> help >> bla bla >> >> and select ATMEL_PIT from the platform's Kconfig. >> > > Well, the goal is actually to allow people to unselect it so we don't > want the platform to select it. Why do you need people to unselect it? The goal of the Kconfig here is to be silent except in the case the COMPILE_TEST option is set for cross-compilation test coverage. We are migrating all these options to this format. Please make it silent. -- <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-08 7:23 ` Daniel Lezcano @ 2018-01-08 8:22 ` Boris Brezillon -1 siblings, 0 replies; 26+ messages in thread From: Boris Brezillon @ 2018-01-08 8:22 UTC (permalink / raw) To: linux-arm-kernel On Mon, 8 Jan 2018 08:23:02 +0100 Daniel Lezcano <daniel.lezcano@linaro.org> wrote: > On 07/01/2018 19:44, Alexandre Belloni wrote: > > On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: > >> On 05/01/2018 15:30, Alexandre Belloni wrote: > >>> With the new TCB clocksource driver, atmel platforms are now able to boot > >>> without the PIT driver. Allow unselecting it. > >>> > >>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > >>> --- > >>> drivers/clocksource/Kconfig | 9 ++++++++- > >>> 1 file changed, 8 insertions(+), 1 deletion(-) > >>> > >>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > >>> index 5609572e0236..55ccfa0ba63b 100644 > >>> --- a/drivers/clocksource/Kconfig > >>> +++ b/drivers/clocksource/Kconfig > >>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > >>> > >>> config ATMEL_PIT > >>> select TIMER_OF if OF > >>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 > >>> + bool "Atmel Periodic Interval Timer (PIT)" > >>> + depends on SOC_AT91SAM9 || SOC_SAMA5 > >>> + default SOC_AT91SAM9 || SOC_SAMA5 > >>> + help > >>> + Select this to get a clocksource based on the Atmel Periodic Interval > >>> + Timer. It has a relatively low resolution and the TC Block clocksource > >>> + should be preferred. > >>> + It also provides a clock event device. > >> > >> Please conform to the format: > >> > >> config ATMEL_PIT > >> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST > >> select ... > >> help > >> bla bla > >> > >> and select ATMEL_PIT from the platform's Kconfig. > >> > > > > Well, the goal is actually to allow people to unselect it so we don't > > want the platform to select it. > > Why do you need people to unselect it? Because we have 2 possible clocksource for atmel platforms: the PIT or the TCB, if the TCB is selected there's no point in compiling the PIT driver. > > The goal of the Kconfig here is to be silent except in the case the > COMPILE_TEST option is set for cross-compilation test coverage. > > We are migrating all these options to this format. Please make it silent. > > ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-08 8:22 ` Boris Brezillon 0 siblings, 0 replies; 26+ messages in thread From: Boris Brezillon @ 2018-01-08 8:22 UTC (permalink / raw) To: Daniel Lezcano Cc: Alexandre Belloni, Thomas Gleixner, Nicolas Ferre, linux-arm-kernel, linux-kernel On Mon, 8 Jan 2018 08:23:02 +0100 Daniel Lezcano <daniel.lezcano@linaro.org> wrote: > On 07/01/2018 19:44, Alexandre Belloni wrote: > > On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: > >> On 05/01/2018 15:30, Alexandre Belloni wrote: > >>> With the new TCB clocksource driver, atmel platforms are now able to boot > >>> without the PIT driver. Allow unselecting it. > >>> > >>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> > >>> --- > >>> drivers/clocksource/Kconfig | 9 ++++++++- > >>> 1 file changed, 8 insertions(+), 1 deletion(-) > >>> > >>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > >>> index 5609572e0236..55ccfa0ba63b 100644 > >>> --- a/drivers/clocksource/Kconfig > >>> +++ b/drivers/clocksource/Kconfig > >>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK > >>> > >>> config ATMEL_PIT > >>> select TIMER_OF if OF > >>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 > >>> + bool "Atmel Periodic Interval Timer (PIT)" > >>> + depends on SOC_AT91SAM9 || SOC_SAMA5 > >>> + default SOC_AT91SAM9 || SOC_SAMA5 > >>> + help > >>> + Select this to get a clocksource based on the Atmel Periodic Interval > >>> + Timer. It has a relatively low resolution and the TC Block clocksource > >>> + should be preferred. > >>> + It also provides a clock event device. > >> > >> Please conform to the format: > >> > >> config ATMEL_PIT > >> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST > >> select ... > >> help > >> bla bla > >> > >> and select ATMEL_PIT from the platform's Kconfig. > >> > > > > Well, the goal is actually to allow people to unselect it so we don't > > want the platform to select it. > > Why do you need people to unselect it? Because we have 2 possible clocksource for atmel platforms: the PIT or the TCB, if the TCB is selected there's no point in compiling the PIT driver. > > The goal of the Kconfig here is to be silent except in the case the > COMPILE_TEST option is set for cross-compilation test coverage. > > We are migrating all these options to this format. Please make it silent. > > ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT 2018-01-08 8:22 ` Boris Brezillon @ 2018-01-08 8:53 ` Daniel Lezcano -1 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-08 8:53 UTC (permalink / raw) To: linux-arm-kernel On 08/01/2018 09:22, Boris Brezillon wrote: > On Mon, 8 Jan 2018 08:23:02 +0100 > Daniel Lezcano <daniel.lezcano@linaro.org> wrote: > >> On 07/01/2018 19:44, Alexandre Belloni wrote: >>> On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: >>>> On 05/01/2018 15:30, Alexandre Belloni wrote: >>>>> With the new TCB clocksource driver, atmel platforms are now able to boot >>>>> without the PIT driver. Allow unselecting it. >>>>> >>>>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> >>>>> --- >>>>> drivers/clocksource/Kconfig | 9 ++++++++- >>>>> 1 file changed, 8 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig >>>>> index 5609572e0236..55ccfa0ba63b 100644 >>>>> --- a/drivers/clocksource/Kconfig >>>>> +++ b/drivers/clocksource/Kconfig >>>>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK >>>>> >>>>> config ATMEL_PIT >>>>> select TIMER_OF if OF >>>>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 >>>>> + bool "Atmel Periodic Interval Timer (PIT)" >>>>> + depends on SOC_AT91SAM9 || SOC_SAMA5 >>>>> + default SOC_AT91SAM9 || SOC_SAMA5 >>>>> + help >>>>> + Select this to get a clocksource based on the Atmel Periodic Interval >>>>> + Timer. It has a relatively low resolution and the TC Block clocksource >>>>> + should be preferred. >>>>> + It also provides a clock event device. >>>> >>>> Please conform to the format: >>>> >>>> config ATMEL_PIT >>>> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST >>>> select ... >>>> help >>>> bla bla >>>> >>>> and select ATMEL_PIT from the platform's Kconfig. >>>> >>> >>> Well, the goal is actually to allow people to unselect it so we don't >>> want the platform to select it. >> >> Why do you need people to unselect it? > > Because we have 2 possible clocksource for atmel platforms: the PIT or > the TCB, if the TCB is selected there's no point in compiling the PIT > driver. Why the platform's Kconfig can't do that ? -- <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT @ 2018-01-08 8:53 ` Daniel Lezcano 0 siblings, 0 replies; 26+ messages in thread From: Daniel Lezcano @ 2018-01-08 8:53 UTC (permalink / raw) To: Boris Brezillon Cc: Alexandre Belloni, Thomas Gleixner, Nicolas Ferre, linux-arm-kernel, linux-kernel On 08/01/2018 09:22, Boris Brezillon wrote: > On Mon, 8 Jan 2018 08:23:02 +0100 > Daniel Lezcano <daniel.lezcano@linaro.org> wrote: > >> On 07/01/2018 19:44, Alexandre Belloni wrote: >>> On 07/01/2018 at 19:07:13 +0100, Daniel Lezcano wrote: >>>> On 05/01/2018 15:30, Alexandre Belloni wrote: >>>>> With the new TCB clocksource driver, atmel platforms are now able to boot >>>>> without the PIT driver. Allow unselecting it. >>>>> >>>>> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> >>>>> --- >>>>> drivers/clocksource/Kconfig | 9 ++++++++- >>>>> 1 file changed, 8 insertions(+), 1 deletion(-) >>>>> >>>>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig >>>>> index 5609572e0236..55ccfa0ba63b 100644 >>>>> --- a/drivers/clocksource/Kconfig >>>>> +++ b/drivers/clocksource/Kconfig >>>>> @@ -381,7 +381,14 @@ config ARMV7M_SYSTICK >>>>> >>>>> config ATMEL_PIT >>>>> select TIMER_OF if OF >>>>> - def_bool SOC_AT91SAM9 || SOC_SAMA5 >>>>> + bool "Atmel Periodic Interval Timer (PIT)" >>>>> + depends on SOC_AT91SAM9 || SOC_SAMA5 >>>>> + default SOC_AT91SAM9 || SOC_SAMA5 >>>>> + help >>>>> + Select this to get a clocksource based on the Atmel Periodic Interval >>>>> + Timer. It has a relatively low resolution and the TC Block clocksource >>>>> + should be preferred. >>>>> + It also provides a clock event device. >>>> >>>> Please conform to the format: >>>> >>>> config ATMEL_PIT >>>> bool "Atmel Periodic Interval Timer (PIT)" if COMPILE_TEST >>>> select ... >>>> help >>>> bla bla >>>> >>>> and select ATMEL_PIT from the platform's Kconfig. >>>> >>> >>> Well, the goal is actually to allow people to unselect it so we don't >>> want the platform to select it. >> >> Why do you need people to unselect it? > > Because we have 2 possible clocksource for atmel platforms: the PIT or > the TCB, if the TCB is selected there's no point in compiling the PIT > driver. Why the platform's Kconfig can't do that ? -- <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog ^ permalink raw reply [flat|nested] 26+ messages in thread
* [PATCH v2 4/6] ARM: configs: at91: use new TCB timer driver 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel Unselecting ATMEL_TCLIB switches the TCB timer driver from tcb_clksrc to timer-atmel-tcb. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/at91_dt_defconfig | 1 - arch/arm/configs/sama5_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index e4b1be66b3f5..09f262e59fef 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -64,7 +64,6 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 6529cb43e0fd..81594322f3a0 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -76,7 +76,6 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y CONFIG_EEPROM_AT24=y CONFIG_SCSI=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 4/6] ARM: configs: at91: use new TCB timer driver @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni Unselecting ATMEL_TCLIB switches the TCB timer driver from tcb_clksrc to timer-atmel-tcb. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/at91_dt_defconfig | 1 - arch/arm/configs/sama5_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index e4b1be66b3f5..09f262e59fef 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -64,7 +64,6 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 6529cb43e0fd..81594322f3a0 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -76,7 +76,6 @@ CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y CONFIG_EEPROM_AT24=y CONFIG_SCSI=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 5/6] ARM: configs: at91: sama5: unselect ATMEL_PIT 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel The PIT is not required anymore to successfully boot and may actually harm in case preempt-rt is used because the PIT interrupt is shared. Disable it so the TCB clocksource is used. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/sama5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 81594322f3a0..e6b984f18002 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -198,6 +198,7 @@ CONFIG_RTC_DRV_AT91RM9200=y CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y CONFIG_AT_XDMAC=y +# CONFIG_ATMEL_PIT is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 5/6] ARM: configs: at91: sama5: unselect ATMEL_PIT @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni The PIT is not required anymore to successfully boot and may actually harm in case preempt-rt is used because the PIT interrupt is shared. Disable it so the TCB clocksource is used. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/sama5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 81594322f3a0..e6b984f18002 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -198,6 +198,7 @@ CONFIG_RTC_DRV_AT91RM9200=y CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y CONFIG_AT_XDMAC=y +# CONFIG_ATMEL_PIT is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 6/6] ARM: configs: at91: at91_dt unselect ATMEL_PIT 2018-01-05 14:30 ` Alexandre Belloni @ 2018-01-05 14:30 ` Alexandre Belloni -1 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: linux-arm-kernel The PIT is not required anymore to successfully boot and may actually harm in case preempt-rt is used because the PIT interrupt is shared. Disable it so the TCB clocksource is used. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/at91_dt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 09f262e59fef..3ec7afe7a6c9 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -181,6 +181,7 @@ CONFIG_RTC_DRV_AT91RM9200=y CONFIG_RTC_DRV_AT91SAM9=y CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y +# CONFIG_ATMEL_PIT is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
* [PATCH v2 6/6] ARM: configs: at91: at91_dt unselect ATMEL_PIT @ 2018-01-05 14:30 ` Alexandre Belloni 0 siblings, 0 replies; 26+ messages in thread From: Alexandre Belloni @ 2018-01-05 14:30 UTC (permalink / raw) To: Daniel Lezcano Cc: Thomas Gleixner, Nicolas Ferre, Boris Brezillon, linux-arm-kernel, linux-kernel, Alexandre Belloni The PIT is not required anymore to successfully boot and may actually harm in case preempt-rt is used because the PIT interrupt is shared. Disable it so the TCB clocksource is used. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> --- arch/arm/configs/at91_dt_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 09f262e59fef..3ec7afe7a6c9 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -181,6 +181,7 @@ CONFIG_RTC_DRV_AT91RM9200=y CONFIG_RTC_DRV_AT91SAM9=y CONFIG_DMADEVICES=y CONFIG_AT_HDMAC=y +# CONFIG_ATMEL_PIT is not set # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y -- 2.15.1 ^ permalink raw reply related [flat|nested] 26+ messages in thread
end of thread, other threads:[~2018-01-08 8:53 UTC | newest] Thread overview: 26+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-01-05 14:30 [PATCH v2 0/6] clocksource: rework Atmel TCB timer driver Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-05 14:30 ` [PATCH v2 1/6] ARM: at91: add TCB registers definitions Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-07 11:59 ` Philippe Ombredanne 2018-01-07 11:59 ` Philippe Ombredanne 2018-01-05 14:30 ` [PATCH v2 2/6] clocksource/drivers: Add a new driver for the Atmel ARM TC blocks Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-05 14:30 ` [PATCH v2 3/6] clocksource/drivers: atmel-pit: allow unselecting ATMEL_PIT Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-07 18:07 ` Daniel Lezcano 2018-01-07 18:07 ` Daniel Lezcano 2018-01-07 18:44 ` Alexandre Belloni 2018-01-07 18:44 ` Alexandre Belloni 2018-01-08 7:23 ` Daniel Lezcano 2018-01-08 7:23 ` Daniel Lezcano 2018-01-08 8:22 ` Boris Brezillon 2018-01-08 8:22 ` Boris Brezillon 2018-01-08 8:53 ` Daniel Lezcano 2018-01-08 8:53 ` Daniel Lezcano 2018-01-05 14:30 ` [PATCH v2 4/6] ARM: configs: at91: use new TCB timer driver Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-05 14:30 ` [PATCH v2 5/6] ARM: configs: at91: sama5: unselect ATMEL_PIT Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni 2018-01-05 14:30 ` [PATCH v2 6/6] ARM: configs: at91: at91_dt " Alexandre Belloni 2018-01-05 14:30 ` Alexandre Belloni
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.