Просмотр исходного кода

linux: start the TPU counters on h8300, so the clocksource runs

h8300_tpu.c programs the two cascaded channels and then never starts
them.  The H8S/2678 manual is explicit in section 11.4.1 -- "When one of
bits CST0 to CST5 is set to 1 in TSTR, the TCNT counter for the
corresponding channel starts counting" -- and figure 11.17, the cascaded
operation procedure, has exactly two steps: set TPSC in the upper
channel's TCR to B'1111, then set the CST bit in TSTR for both channels.
The driver does the first and omits the second, and TSTR is all zeroes
out of reset.

So the counter never moves, clocksource_read returns the same value for
ever, and any wait that goes through it hangs.  On the EDOSK-2674 that
is anything past init: clock_gettime(CLOCK_MONOTONIC) reads 0.000000000
three times in a row and sleep(1) never returns.  It is why booting this
board needs clocksource=jiffies -- with this patch it does not.

The driver could not have done it anyway: the node hands it the two
channel register blocks and nothing else, while TSTR lives at 0xffffc0
in the block the channels share.  Add that block as a third reg entry
and name the two channels, then set and clear their CST bits in the
clocksource's enable and disable.  h8300_timer16.c, the sibling driver
the H8/300H boards use, has done it this way all along -- it takes a
REG_COMM range and a renesas,channel property and keeps an enb mask.
That is also why nobody noticed: every H8/300H board goes through
timer16, and the TPU path only ever ran on the two H8S boards.

The gap was there from 618b902d8c09 ("h8300: clocksource", 2015) until
the architecture was removed in 1c4b5ecb7ea1 (v5.19), through the
conversion to iowrite8 and TIMER_OF_DECLARE in between.  There is no
upstream left to send it to.

Both H8S boards get the DTS change; only edosk2674 is built here.

Signed-off-by: Waldemar Brodkorb <wbx@openadk.org>
ramin 4 дней назад
Родитель
Сommit
30f22b3199
1 измененных файлов с 108 добавлено и 0 удалено
  1. 108 0
      target/linux/patches/4.4.302/h8300-tpu-clocksource.patch

+ 108 - 0
target/linux/patches/4.4.302/h8300-tpu-clocksource.patch

@@ -0,0 +1,108 @@
+--- linux-4.4.302.orig/drivers/clocksource/h8300_tpu.c
++++ linux-4.4.302/drivers/clocksource/h8300_tpu.c
+@@ -31,12 +31,17 @@
+ #define TGRC	12
+ #define TGRD	14
+ 
++/* Common registers */
++#define TSTR	0
++
+ struct tpu_priv {
+ 	struct platform_device *pdev;
+ 	struct clocksource cs;
+ 	struct clk *clk;
+ 	unsigned long mapbase1;
+ 	unsigned long mapbase2;
++	unsigned long mapcommon;
++	unsigned char enb;
+ 	raw_spinlock_t lock;
+ 	unsigned int cs_enabled;
+ };
+@@ -100,6 +105,8 @@
+ 	ctrl_outw(0, p->mapbase2 + TCNT);
+ 	ctrl_outb(0x0f, p->mapbase1 + TCR);
+ 	ctrl_outb(0x03, p->mapbase2 + TCR);
++	ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
++		  p->mapcommon + TSTR);
+ 
+ 	p->cs_enabled = true;
+ 	return 0;
+@@ -111,6 +118,8 @@
+ 
+ 	WARN_ON(!p->cs_enabled);
+ 
++	ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
++		  p->mapcommon + TSTR);
+ 	ctrl_outb(0, p->mapbase1 + TCR);
+ 	ctrl_outb(0, p->mapbase2 + TCR);
+ 	p->cs_enabled = false;
+@@ -118,20 +127,34 @@
+ 
+ #define CH_L 0
+ #define CH_H 1
++#define REG_COMM 2
+ 
+ static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
+ {
+-	struct resource *res[2];
++	struct resource *res[3];
++	u32 ch[2];
++	int i;
+ 
+ 	p->pdev = pdev;
+ 
+ 	res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
+ 	res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
+-	if (!res[CH_L] || !res[CH_H]) {
++	res[REG_COMM] = platform_get_resource(p->pdev, IORESOURCE_MEM,
++					      REG_COMM);
++	if (!res[CH_L] || !res[CH_H] || !res[REG_COMM]) {
+ 		dev_err(&p->pdev->dev, "failed to get I/O memory\n");
+ 		return -ENXIO;
+ 	}
+ 
++	for (i = 0; i < 2; i++) {
++		if (of_property_read_u32_index(p->pdev->dev.of_node,
++					       "renesas,channel", i, &ch[i]) ||
++		    ch[i] > 5) {
++			dev_err(&p->pdev->dev, "renesas,channel missing\n");
++			return -EINVAL;
++		}
++	}
++
+ 	p->clk = clk_get(&p->pdev->dev, "fck");
+ 	if (IS_ERR(p->clk)) {
+ 		dev_err(&p->pdev->dev, "can't get clk\n");
+@@ -140,6 +163,8 @@
+ 
+ 	p->mapbase1 = res[CH_L]->start;
+ 	p->mapbase2 = res[CH_H]->start;
++	p->mapcommon = res[REG_COMM]->start;
++	p->enb = BIT(ch[CH_L]) | BIT(ch[CH_H]);
+ 
+ 	p->cs.name = pdev->name;
+ 	p->cs.rating = 200;
+--- linux-4.4.302.orig/arch/h8300/boot/dts/edosk2674.dts
++++ linux-4.4.302/arch/h8300/boot/dts/edosk2674.dts
+@@ -70,7 +70,8 @@
+ 
+ 	tpu: timer@ffffe0 {
+ 		compatible = "renesas,tpu";
+-		reg = <0xffffe0 16>, <0xfffff0 12>;
++		reg = <0xffffe0 16>, <0xfffff0 12>, <0xffffc0 8>;
++		renesas,channel = <1 2>;
+ 		clocks = <&fclk>;
+ 		clock-names = "fck";
+ 	};
+--- linux-4.4.302.orig/arch/h8300/boot/dts/h8s_sim.dts
++++ linux-4.4.302/arch/h8300/boot/dts/h8s_sim.dts
+@@ -69,7 +69,8 @@
+ 
+ 	tpu: timer@ffffe0 {
+ 		compatible = "renesas,tpu";
+-		reg = <0xffffe0 16>, <0xfffff0 12>;
++		reg = <0xffffe0 16>, <0xfffff0 12>, <0xffffc0 8>;
++		renesas,channel = <1 2>;
+ 		clocks = <&fclk>;
+ 		clock-names = "fck";
+ 	};