From: AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> Date: 2022-06-13 15:55:13
In an effort to give some love to the apparently forgotten MT6795 SoC,
I am upstreaming more components that are necessary to support platforms
powered by this one apart from a simple boot to serial console.
This series introduces support to start the System Timer for the CPU
cores found in various MediaTek SoCs including, but not limited to the
MT6795 Helio X10 - and will most probably unblock many developers for
the upstreaming of various platforms.
For a broad overview of why/what/when, please look at the description
of patch [2/2] in this series.
Tested on a MT6795 Sony Xperia M5 (codename "Holly") smartphone.
Changes in v4:
- Changed statement in documentation, now saying:
"MediaTek SoCs have different timers on different platforms"
Changes in v3:
- Merged mtk_cpux_{enable,disable}_irq() as one mtk_cpux_set_irq() function
as suggested by Matthias
Changes in v2:
- Added back a lost line in commit 2/2 (sorry, commit didn't get amended...!)
- Tested again for safety
AngeloGioacchino Del Regno (2):
dt-bindings: timer: mediatek: Add CPUX System Timer and MT6795
compatible
clocksource/drivers/timer-mediatek: Implement CPUXGPT timers
.../bindings/timer/mediatek,mtk-timer.txt | 6 +-
drivers/clocksource/timer-mediatek.c | 114 ++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
--
2.35.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> Date: 2022-06-13 15:55:04
Some MediaTek platforms with a buggy TrustZone ATF firmware will not
initialize the AArch64 System Timer correctly: in these cases, the
System Timer address is correctly programmed, as well as the CNTFRQ_EL0
register (reading 13MHz, as it should be), but the assigned hardware
timers are never started before (or after) booting Linux.
In this condition, any call to function get_cycles() will be returning
zero, as CNTVCT_EL0 will always read zero.
One common critical symptom of that is trying to use the udelay()
function (calling __delay()), which executes the following loop:
start = get_cycles();
while ((get_cycles() - start) < cycles)
cpu_relax();
which, when CNTVCT_EL0 always reads zero, translates to:
while((0 - 0) < 0) ==> while(0 < 0)
... generating an infinite loop, even though zero is never less
than zero, but always equal to it (this has to be researched,
but it's out of the scope of this commit).
To fix this issue on the affected MediaTek platforms, the solution
is to simply start the timers that are designed to be System Timer(s).
These timers, downstream, are called "CPUXGPT" and there is one
timer per CPU core; luckily, it is not necessary to set a start bit
on each CPUX General Purpose Timer, but it's conveniently enough to:
- Set the clock divider (input = 26MHz, divider = 2, output = 13MHz);
- Set the ENABLE bit on a global register (starts all CPUX timers).
The only small hurdle with this setup is that it's all done through
the MCUSYS wrapper, where it is needed, for each read or write, to
select a register address (by writing it to an index register) and
then to perform any R/W on a "CON" register.
For example, writing "0x1" to the CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Write 0x1 to mcusys CON register
Reading from CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Read mcusys CON register.
Finally, starting this timer makes platforms affected by this issue
to work correctly.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
---
drivers/clocksource/timer-mediatek.c | 114 +++++++++++++++++++++++++++
1 file changed, 114 insertions(+)
@@ -72,6 +85,52 @@staticvoid__iomem*gpt_sched_reg__read_mostly;+staticu32mtk_cpux_readl(u32reg_idx,structtimer_of*to)+{+writel(reg_idx,timer_of_base(to)+CPUX_IDX_REG);+returnreadl(timer_of_base(to)+CPUX_CON_REG);+}++staticvoidmtk_cpux_writel(u32val,u32reg_idx,structtimer_of*to)+{+writel(reg_idx,timer_of_base(to)+CPUX_IDX_REG);+writel(val,timer_of_base(to)+CPUX_CON_REG);+}++staticvoidmtk_cpux_set_irq(structtimer_of*to,boolenable)+{+constunsignedlong*irq_mask=cpumask_bits(cpu_possible_mask);+u32val;++val=mtk_cpux_readl(CPUX_IDX_GLOBAL_IRQ,to);++if(enable)+val|=*irq_mask;+else+val&=~(*irq_mask);++mtk_cpux_writel(val,CPUX_IDX_GLOBAL_IRQ,to);+}++staticintmtk_cpux_clkevt_shutdown(structclock_event_device*clkevt)+{+/* Clear any irq */+mtk_cpux_set_irq(to_timer_of(clkevt),false);++/*+*DisablingCPUXGPTtimerwillcrashtheplatform,especially+*ifTrustedFirmwareisusingit(usually,forsleepstates),+*soweonlymasktheIRQandcallitaday.+*/+return0;+}++staticintmtk_cpux_clkevt_resume(structclock_event_device*clkevt)+{+mtk_cpux_set_irq(to_timer_of(clkevt),true);+return0;+}+staticvoidmtk_syst_ack_irq(structtimer_of*to){/* Clear and disable interrupt */
@@ -281,6 +340,60 @@ static struct timer_of to = {},};+staticint__initmtk_cpux_init(structdevice_node*node)+{+staticstructtimer_ofto_cpux;+u32freq,val;+intret;++/*+*Thereareper-cpuinterruptsfortheCPUXGeneralPurposeTimer+*butsincethistimerfeedstheAArch64SystemTimerwecanrely+*ontheCPUtimerPPIsaswell,sowedon'tdeclareTIMER_OF_IRQ.+*/+to_cpux.flags=TIMER_OF_BASE|TIMER_OF_CLOCK;+to_cpux.clkevt.name="mtk-cpuxgpt";+to_cpux.clkevt.rating=10;+to_cpux.clkevt.cpumask=cpu_possible_mask;+to_cpux.clkevt.set_state_shutdown=mtk_cpux_clkevt_shutdown;+to_cpux.clkevt.tick_resume=mtk_cpux_clkevt_resume;++/* If this fails, bad things are about to happen... */+ret=timer_of_init(node,&to_cpux);+if(ret){+WARN(1,"Cannot start CPUX timers.\n");+returnret;+}++/*+*Checkifwe'regivenaclockwiththerightfrequencyforthis+*timer,otherwisewarnbutkeepgoingwiththesetupanyway,as+*thatmakesitpossibletostillbootthekernel,eventhough+*itmaynotworkcorrectly(randomlockups,etc).+*ThereasonbehindthisisthathavinganearlyUARTmaynotbe+*possibleforeveryoneandthisgivesachancetoretrievekmsg+*foreventualdebuggingevenonconsumerdevices.+*/+freq=timer_of_rate(&to_cpux);+if(freq>13000000)+WARN(1,"Requested unsupported timer frequency %u\n",freq);++/* Clock input is 26MHz, set DIV2 to achieve 13MHz clock */+val=mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL,&to_cpux);+val&=~CPUX_CLK_DIV_MASK;+val|=CPUX_CLK_DIV2;+mtk_cpux_writel(val,CPUX_IDX_GLOBAL_CTRL,&to_cpux);++/* Enable all CPUXGPT timers */+val=mtk_cpux_readl(CPUX_IDX_GLOBAL_CTRL,&to_cpux);+mtk_cpux_writel(val|CPUX_ENABLE,CPUX_IDX_GLOBAL_CTRL,&to_cpux);++clockevents_config_and_register(&to_cpux.clkevt,timer_of_rate(&to_cpux),+TIMER_SYNC_TICKS,0xffffffff);++return0;+}+staticint__initmtk_syst_init(structdevice_node*node){intret;
@@ -339,3 +452,4 @@ static int __init mtk_gpt_init(struct device_node *node)}TIMER_OF_DECLARE(mtk_mt6577,"mediatek,mt6577-timer",mtk_gpt_init);TIMER_OF_DECLARE(mtk_mt6765,"mediatek,mt6765-timer",mtk_syst_init);+TIMER_OF_DECLARE(mtk_mt6795,"mediatek,mt6795-systimer",mtk_cpux_init);
--
2.35.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> Date: 2022-06-13 15:55:44
Document the "CPUXGPT" CPU General Purpose Timer, used as ARM/ARM64
System Timer on MediaTek platforms and add the MT6795 compatible for it.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Acked-by: Rob Herring <robh@kernel.org>
Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>
---
.../devicetree/bindings/timer/mediatek,mtk-timer.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
@@ -1,7 +1,8 @@ MediaTek Timers ----------------MediaTek SoCs have two different timers on different platforms,+MediaTek SoCs have different timers on different platforms,+- CPUX (ARM/ARM64 System Timer) - GPT (General Purpose Timer) - SYST (System Timer)
@@ -29,6 +30,9 @@ Required properties: * "mediatek,mt7629-timer" for MT7629 compatible timers (SYST) * "mediatek,mt6765-timer" for MT6765 and all above compatible timers (SYST)+ For those SoCs that use CPUX+ * "mediatek,mt6795-systimer" for MT6795 compatible timers (CPUX)+ - reg: Should contain location and length for timer register. - clocks: Should contain system clock.
--
2.35.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Daniel Lezcano <hidden> Date: 2022-06-14 18:35:55
On 13/06/2022 15:38, AngeloGioacchino Del Regno wrote:
Some MediaTek platforms with a buggy TrustZone ATF firmware will not
initialize the AArch64 System Timer correctly: in these cases, the
System Timer address is correctly programmed, as well as the CNTFRQ_EL0
register (reading 13MHz, as it should be), but the assigned hardware
timers are never started before (or after) booting Linux.
In this condition, any call to function get_cycles() will be returning
zero, as CNTVCT_EL0 will always read zero.
One common critical symptom of that is trying to use the udelay()
function (calling __delay()), which executes the following loop:
start = get_cycles();
while ((get_cycles() - start) < cycles)
cpu_relax();
which, when CNTVCT_EL0 always reads zero, translates to:
while((0 - 0) < 0) ==> while(0 < 0)
... generating an infinite loop, even though zero is never less
than zero, but always equal to it (this has to be researched,
but it's out of the scope of this commit).
To fix this issue on the affected MediaTek platforms, the solution
is to simply start the timers that are designed to be System Timer(s).
These timers, downstream, are called "CPUXGPT" and there is one
timer per CPU core; luckily, it is not necessary to set a start bit
on each CPUX General Purpose Timer, but it's conveniently enough to:
- Set the clock divider (input = 26MHz, divider = 2, output = 13MHz);
- Set the ENABLE bit on a global register (starts all CPUX timers).
The only small hurdle with this setup is that it's all done through
the MCUSYS wrapper, where it is needed, for each read or write, to
select a register address (by writing it to an index register) and
then to perform any R/W on a "CON" register.
For example, writing "0x1" to the CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Write 0x1 to mcusys CON register
Reading from CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Read mcusys CON register.
Finally, starting this timer makes platforms affected by this issue
to work correctly.
From: AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> Date: 2022-06-15 09:04:59
Il 14/06/22 20:35, Daniel Lezcano ha scritto:
On 13/06/2022 15:38, AngeloGioacchino Del Regno wrote:
quoted
Some MediaTek platforms with a buggy TrustZone ATF firmware will not
initialize the AArch64 System Timer correctly: in these cases, the
System Timer address is correctly programmed, as well as the CNTFRQ_EL0
register (reading 13MHz, as it should be), but the assigned hardware
timers are never started before (or after) booting Linux.
In this condition, any call to function get_cycles() will be returning
zero, as CNTVCT_EL0 will always read zero.
One common critical symptom of that is trying to use the udelay()
function (calling __delay()), which executes the following loop:
start = get_cycles();
while ((get_cycles() - start) < cycles)
cpu_relax();
which, when CNTVCT_EL0 always reads zero, translates to:
while((0 - 0) < 0) ==> while(0 < 0)
... generating an infinite loop, even though zero is never less
than zero, but always equal to it (this has to be researched,
but it's out of the scope of this commit).
To fix this issue on the affected MediaTek platforms, the solution
is to simply start the timers that are designed to be System Timer(s).
These timers, downstream, are called "CPUXGPT" and there is one
timer per CPU core; luckily, it is not necessary to set a start bit
on each CPUX General Purpose Timer, but it's conveniently enough to:
- Set the clock divider (input = 26MHz, divider = 2, output = 13MHz);
- Set the ENABLE bit on a global register (starts all CPUX timers).
The only small hurdle with this setup is that it's all done through
the MCUSYS wrapper, where it is needed, for each read or write, to
select a register address (by writing it to an index register) and
then to perform any R/W on a "CON" register.
For example, writing "0x1" to the CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Write 0x1 to mcusys CON register
Reading from CPUXGPT register offset 0x4:
- Write 0x4 to mcusys INDEX register
- Read mcusys CON register.
Finally, starting this timer makes platforms affected by this issue
to work correctly.
From: AngeloGioacchino Del Regno
<angelogioacchino.delregno@collabora.com> Date: 2022-07-08 08:45:33
Il 13/06/22 15:38, AngeloGioacchino Del Regno ha scritto:
In an effort to give some love to the apparently forgotten MT6795 SoC,
I am upstreaming more components that are necessary to support platforms
powered by this one apart from a simple boot to serial console.
This series introduces support to start the System Timer for the CPU
cores found in various MediaTek SoCs including, but not limited to the
MT6795 Helio X10 - and will most probably unblock many developers for
the upstreaming of various platforms.
For a broad overview of why/what/when, please look at the description
of patch [2/2] in this series.
Tested on a MT6795 Sony Xperia M5 (codename "Holly") smartphone.
Changes in v4:
- Changed statement in documentation, now saying:
"MediaTek SoCs have different timers on different platforms"
Changes in v3:
- Merged mtk_cpux_{enable,disable}_irq() as one mtk_cpux_set_irq() function
as suggested by Matthias
Changes in v2:
- Added back a lost line in commit 2/2 (sorry, commit didn't get amended...!)
- Tested again for safety
AngeloGioacchino Del Regno (2):
dt-bindings: timer: mediatek: Add CPUX System Timer and MT6795
compatible
clocksource/drivers/timer-mediatek: Implement CPUXGPT timers
.../bindings/timer/mediatek,mtk-timer.txt | 6 +-
drivers/clocksource/timer-mediatek.c | 114 ++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
Gentle ping for this one - I need it to start upstreaming devicetrees for
that MT6795 Xperia M5 smartphone, or it won't be able to boot.
Thanks,
Angelo
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
From: Daniel Lezcano <hidden> Date: 2022-07-15 22:42:26
On 08/07/2022 10:45, AngeloGioacchino Del Regno wrote:
Il 13/06/22 15:38, AngeloGioacchino Del Regno ha scritto:
quoted
In an effort to give some love to the apparently forgotten MT6795 SoC,
I am upstreaming more components that are necessary to support platforms
powered by this one apart from a simple boot to serial console.
This series introduces support to start the System Timer for the CPU
cores found in various MediaTek SoCs including, but not limited to the
MT6795 Helio X10 - and will most probably unblock many developers for
the upstreaming of various platforms.
For a broad overview of why/what/when, please look at the description
of patch [2/2] in this series.
Tested on a MT6795 Sony Xperia M5 (codename "Holly") smartphone.
Changes in v4:
- Changed statement in documentation, now saying:
"MediaTek SoCs have different timers on different platforms"
Changes in v3:
- Merged mtk_cpux_{enable,disable}_irq() as one mtk_cpux_set_irq()
function
as suggested by Matthias
Changes in v2:
- Added back a lost line in commit 2/2 (sorry, commit didn't get
amended...!)
- Tested again for safety
AngeloGioacchino Del Regno (2):
dt-bindings: timer: mediatek: Add CPUX System Timer and MT6795
compatible
clocksource/drivers/timer-mediatek: Implement CPUXGPT timers
.../bindings/timer/mediatek,mtk-timer.txt | 6 +-
drivers/clocksource/timer-mediatek.c | 114 ++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
Gentle ping for this one - I need it to start upstreaming devicetrees for
that MT6795 Xperia M5 smartphone, or it won't be able to boot.