Patch "clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled" has been added to the 4.19-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled

to the 4.19-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     clocksource-drivers-sh_cmt-make-sure-channel-clock-s.patch
and it can be found in the queue-4.19 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 259ae1302939c022dff87838c833dae7cd74f885
Author: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
Date:   Thu Dec 10 20:46:48 2020 +0100

    clocksource/drivers/sh_cmt: Make sure channel clock supply is enabled
    
    [ Upstream commit 2a97d55333e4299f32c98cca6dc5c4db1c5855fc ]
    
    The Renesas Compare Match Timer 0 and 1 (CMT0/1) variants have a
    register to control the clock supply to the individual channels.
    Currently the driver does not touch this register, and relies on the
    documented initial value, which has the clock supply enabled for all
    channels present.
    
    However, when Linux starts on the APE6-EVM development board, only the
    clock supply to the first CMT1 channel is enabled.  Hence the first
    channel (used as a clockevent) works, while the second channel (used as
    a clocksource) does not.  Note that the default system clocksource is
    the Cortex-A15 architectured timer, and the user needs to manually
    switch to the CMT1 clocksource to trigger the broken behavior.
    
    Fix this by removing the fragile dependency on implicit reset and/or
    boot loader state, and by enabling the clock supply explicitly for all
    channels used instead.  This requires postponing the clk_disable() call,
    else the timer's registers cannot be accessed in sh_cmt_setup_channel().
    
    Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
    Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@xxxxxxxxxxxx>
    Signed-off-by: Daniel Lezcano <daniel.lezcano@xxxxxxxxxx>
    Link: https://lore.kernel.org/r/20201210194648.2901899-1-geert+renesas@xxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 7a6d4c4c0feb..0ca8819acc4d 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -239,6 +239,8 @@ static const struct sh_cmt_info sh_cmt_info[] = {
 #define CMCNT 1 /* channel register */
 #define CMCOR 2 /* channel register */
 
+#define CMCLKE	0x1000	/* CLK Enable Register (R-Car Gen2) */
+
 static inline u32 sh_cmt_read_cmstr(struct sh_cmt_channel *ch)
 {
 	if (ch->iostart)
@@ -856,6 +858,7 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
 				unsigned int hwidx, bool clockevent,
 				bool clocksource, struct sh_cmt_device *cmt)
 {
+	u32 value;
 	int ret;
 
 	/* Skip unused channels. */
@@ -885,6 +888,11 @@ static int sh_cmt_setup_channel(struct sh_cmt_channel *ch, unsigned int index,
 		ch->iostart = cmt->mapbase + ch->hwidx * 0x100;
 		ch->ioctrl = ch->iostart + 0x10;
 		ch->timer_bit = 0;
+
+		/* Enable the clock supply to the channel */
+		value = ioread32(cmt->mapbase + CMCLKE);
+		value |= BIT(hwidx);
+		iowrite32(value, cmt->mapbase + CMCLKE);
 		break;
 	}
 
@@ -991,12 +999,10 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
 	else
 		cmt->rate = clk_get_rate(cmt->clk) / 8;
 
-	clk_disable(cmt->clk);
-
 	/* Map the memory resource(s). */
 	ret = sh_cmt_map_memory(cmt);
 	if (ret < 0)
-		goto err_clk_unprepare;
+		goto err_clk_disable;
 
 	/* Allocate and setup the channels. */
 	cmt->num_channels = hweight8(cmt->hw_channels);
@@ -1024,6 +1030,8 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
 		mask &= ~(1 << hwidx);
 	}
 
+	clk_disable(cmt->clk);
+
 	platform_set_drvdata(pdev, cmt);
 
 	return 0;
@@ -1031,6 +1039,8 @@ static int sh_cmt_setup(struct sh_cmt_device *cmt, struct platform_device *pdev)
 err_unmap:
 	kfree(cmt->channels);
 	iounmap(cmt->mapbase);
+err_clk_disable:
+	clk_disable(cmt->clk);
 err_clk_unprepare:
 	clk_unprepare(cmt->clk);
 err_clk_put:



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux