Module Name:    src
Committed By:   jmcneill
Date:           Mon Jul  2 12:49:37 UTC 2018

Modified Files:
        src/sys/arch/arm/samsung: exynos_platform.c mct.c mct_var.h

Log Message:
Add a proper MCT driver rather than relying on ARM Generic Timer (which
may not be functional or even present).


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/arch/arm/samsung/exynos_platform.c
cvs rdiff -u -r1.13 -r1.14 src/sys/arch/arm/samsung/mct.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/samsung/mct_var.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/samsung/exynos_platform.c
diff -u src/sys/arch/arm/samsung/exynos_platform.c:1.9 src/sys/arch/arm/samsung/exynos_platform.c:1.10
--- src/sys/arch/arm/samsung/exynos_platform.c:1.9	Sat Mar 17 18:34:09 2018
+++ src/sys/arch/arm/samsung/exynos_platform.c	Mon Jul  2 12:49:37 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: exynos_platform.c,v 1.9 2018/03/17 18:34:09 ryo Exp $ */
+/* $NetBSD: exynos_platform.c,v 1.10 2018/07/02 12:49:37 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2017 Jared D. McNeill <jmcne...@invisible.ca>
@@ -33,7 +33,7 @@
 #include "ukbd.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: exynos_platform.c,v 1.9 2018/03/17 18:34:09 ryo Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exynos_platform.c,v 1.10 2018/07/02 12:49:37 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,11 +50,10 @@ __KERNEL_RCSID(0, "$NetBSD: exynos_platf
 
 #include <arm/samsung/exynos_reg.h>
 #include <arm/samsung/exynos_var.h>
+#include <arm/samsung/mct_var.h>
 
 #include <evbarm/exynos/platform.h>
 
-#include <arm/cortex/gtmr_var.h>
-
 #include <arm/fdt/arm_fdtvar.h>
 
 #define	EXYNOS5_SWRESET_REG	0x10040400
@@ -123,12 +122,6 @@ exynos5_platform_reset(void)
 	bus_space_write_4(bst, bsh, 0, 1);
 }
 
-static void
-exynos_platform_delay(u_int us)
-{
-	gtmr_delay(us);
-}
-
 static u_int
 exynos_platform_uart_freq(void)
 {
@@ -142,7 +135,7 @@ static const struct arm_platform exynos5
 	.early_putchar = exynos_platform_early_putchar,
 	.device_register = exynos_platform_device_register,
 	.reset = exynos5_platform_reset,
-	.delay = exynos_platform_delay,
+	.delay = mct_delay,
 	.uart_freq = exynos_platform_uart_freq,
 };
 

Index: src/sys/arch/arm/samsung/mct.c
diff -u src/sys/arch/arm/samsung/mct.c:1.13 src/sys/arch/arm/samsung/mct.c:1.14
--- src/sys/arch/arm/samsung/mct.c:1.13	Sun Jul  1 23:21:43 2018
+++ src/sys/arch/arm/samsung/mct.c	Mon Jul  2 12:49:37 2018
@@ -1,11 +1,11 @@
-/*	$NetBSD: mct.c,v 1.13 2018/07/01 23:21:43 jmcneill Exp $	*/
+/*	$NetBSD: mct.c,v 1.14 2018/07/02 12:49:37 jmcneill Exp $	*/
 
 /*-
- * Copyright (c) 2014 The NetBSD Foundation, Inc.
+ * Copyright (c) 2014-2018 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
- * by Reinoud Zandijk.
+ * by Reinoud Zandijk and Jared McNeill.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.13 2018/07/01 23:21:43 jmcneill Exp $");
+__KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.14 2018/07/02 12:49:37 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -50,16 +50,25 @@ __KERNEL_RCSID(1, "$NetBSD: mct.c,v 1.13
 #include <arm/samsung/mct_reg.h>
 #include <arm/samsung/mct_var.h>
 
-#include <arm/cortex/gtmr_intr.h>
-#include <arm/cortex/mpcore_var.h>
-#include <arm/cortex/gtmr_var.h>
-
 #include <dev/fdt/fdtvar.h>
 #include <arm/fdt/arm_fdtvar.h>
 
+static struct mct_softc mct_sc;
+
 static int  mct_match(device_t, cfdata_t, void *);
 static void mct_attach(device_t, device_t, void *);
 
+static u_int mct_get_timecount(struct timecounter *);
+
+static struct timecounter mct_timecounter = {
+	.tc_get_timecount = mct_get_timecount,
+	.tc_counter_mask = ~0u,
+	.tc_frequency = EXYNOS_F_IN_FREQ,
+	.tc_name = "MCT",
+	.tc_quality = 500,
+	.tc_priv = &mct_sc,
+};
+
 CFATTACH_DECL_NEW(exyo_mct, 0, mct_match, mct_attach, NULL, NULL);
 
 static inline uint32_t
@@ -85,20 +94,31 @@ mct_write_global(struct mct_softc *sc, b
 		wreg = MCT_G_CNT_WSTAT;
 		bit  = (o == MCT_G_CNT_L) ? G_CNT_WSTAT_L : G_CNT_WSTAT_U;
 	} else {
-		wreg = MCT_G_WSTAT;
 		switch (o) {
 		case MCT_G_COMP0_L:
+			wreg = MCT_G_WSTAT;
 			bit  = G_WSTAT_COMP0_L;
 			break;
 		case MCT_G_COMP0_U:
+			wreg = MCT_G_WSTAT;
 			bit  = G_WSTAT_COMP0_U;
 			break;
 		case MCT_G_COMP0_ADD_INCR:
+			wreg = MCT_G_WSTAT;
 			bit  = G_WSTAT_ADD_INCR;
 			break;
 		case MCT_G_TCON:
+			wreg = MCT_G_WSTAT;
 			bit  = G_WSTAT_TCON;
 			break;
+		case MCT_G_CNT_L:
+			wreg = MCT_G_CNT_WSTAT;
+			bit  = G_CNT_WSTAT_L;
+			break;
+		case MCT_G_CNT_U:
+			wreg = MCT_G_CNT_WSTAT;
+			bit  = G_CNT_WSTAT_U;
+			break;
 		default:
 			/* all other registers */
 			return;
@@ -120,7 +140,69 @@ mct_write_global(struct mct_softc *sc, b
 static void
 mct_fdt_cpu_hatch(void *priv, struct cpu_info *ci)
 {
-	gtmr_init_cpu_clock(ci);
+	panic("%s: not implemented", __func__);
+}
+
+static int
+mct_intr(void *arg)
+{
+	struct mct_softc * const sc = &mct_sc;
+	struct clockframe *frame = arg;
+
+	mct_write_global(sc, MCT_G_INT_CSTAT, G_INT_CSTAT_CLEAR);
+
+	hardclock(frame);
+
+	return 1;
+}
+
+static u_int
+mct_get_timecount(struct timecounter *tc)
+{
+	struct mct_softc * const sc = tc->tc_priv;
+
+	return mct_read_global(sc, MCT_G_CNT_L);
+}
+
+static uint64_t
+mct_read_gcnt(struct mct_softc *sc)
+{
+	uint32_t gcntl, gcntu;
+
+	do {
+		gcntu = mct_read_global(sc, MCT_G_CNT_U);
+		gcntl = mct_read_global(sc, MCT_G_CNT_L);
+	} while (gcntu != mct_read_global(sc, MCT_G_CNT_U));
+
+	return ((uint64_t)gcntu << 32) | gcntl;
+}
+
+static void
+mct_cpu_initclocks(void)
+{
+	struct mct_softc * const sc = &mct_sc;
+	char intrstr[128];
+
+	if (!fdtbus_intr_str(sc->sc_phandle, 0, intrstr, sizeof(intrstr)))
+		panic("%s: failed to decode interrupt", __func__);
+
+	sc->sc_global_ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_CLOCK,
+	    FDT_INTR_MPSAFE, mct_intr, NULL);
+	if (sc->sc_global_ih == NULL)
+		panic("%s: failed to establish timer interrupt on %s", __func__, intrstr);
+
+	aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr);
+
+	/* Start the timer */
+	const u_int autoinc = sc->sc_freq / hz;
+	const uint64_t comp0 = mct_read_gcnt(sc) + autoinc;
+
+	mct_write_global(sc, MCT_G_TCON, G_TCON_START | G_TCON_COMP0_AUTOINC);
+	mct_write_global(sc, MCT_G_COMP0_ADD_INCR, autoinc);
+	mct_write_global(sc, MCT_G_COMP0_L, (uint32_t)comp0);
+	mct_write_global(sc, MCT_G_COMP0_U, (uint32_t)(comp0 >> 32));
+	mct_write_global(sc, MCT_G_INT_ENB, G_INT_ENB_ENABLE);
+	mct_write_global(sc, MCT_G_TCON, G_TCON_START | G_TCON_COMP0_ENABLE | G_TCON_COMP0_AUTOINC);
 }
 
 static int
@@ -149,9 +231,9 @@ mct_attach(device_t parent, device_t sel
 
 	self->dv_private = sc;
 	sc->sc_dev = self;
+	sc->sc_phandle = faa->faa_phandle;
 	sc->sc_bst = faa->faa_bst;
 	sc->sc_freq = EXYNOS_F_IN_FREQ;
-
 	error = bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh);
 	if (error) {
 		aprint_error(": couldn't map %#llx: %d",
@@ -162,19 +244,31 @@ mct_attach(device_t parent, device_t sel
 	aprint_naive("\n");
 	aprint_normal(": Exynos SoC multi core timer (64 bits)\n");
 
-	/* Start the timer */
-	uint32_t tcon = mct_read_global(sc, MCT_G_TCON);
-	tcon |= G_TCON_START;
-	mct_write_global(sc, MCT_G_TCON, tcon);
-
-	/* Attach ARMv7 generic timer */
-	struct mpcore_attach_args mpcaa = {
-		.mpcaa_name = "armgtmr",
-		.mpcaa_irq = IRQ_GTMR_PPI_VTIMER
-	};
-
-	config_found(self, &mpcaa, NULL);
+	tc_init(&mct_timecounter);
 
 	arm_fdt_cpu_hatch_register(self, mct_fdt_cpu_hatch);
-	arm_fdt_timer_register(gtmr_cpu_initclocks);
+	arm_fdt_timer_register(mct_cpu_initclocks);
+}
+
+void
+mct_delay(u_int n)
+{
+	struct mct_softc * const sc = &mct_sc;
+	uint64_t cur, prev;
+
+	if (sc->sc_bsh == 0)
+		panic("%s: mct driver not attached", __func__);
+
+	const long incs_per_us = sc->sc_freq / 1000000;
+	long ticks = n * incs_per_us;
+
+	prev = mct_read_gcnt(sc);
+	while (ticks > 0) {
+		cur = mct_read_gcnt(sc);
+		if (cur > prev)
+			ticks -= (cur - prev);
+		else
+			ticks -= (UINT64_MAX - cur + prev);
+		prev = cur;
+	}
 }

Index: src/sys/arch/arm/samsung/mct_var.h
diff -u src/sys/arch/arm/samsung/mct_var.h:1.5 src/sys/arch/arm/samsung/mct_var.h:1.6
--- src/sys/arch/arm/samsung/mct_var.h:1.5	Sun Jun 11 01:09:44 2017
+++ src/sys/arch/arm/samsung/mct_var.h	Mon Jul  2 12:49:37 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: mct_var.h,v 1.5 2017/06/11 01:09:44 jmcneill Exp $	*/
+/*	$NetBSD: mct_var.h,v 1.6 2018/07/02 12:49:37 jmcneill Exp $	*/
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -36,11 +36,11 @@
 #include <sys/bus.h>
 #include <sys/device.h>
 
-static struct mct_softc {
+struct mct_softc {
 	device_t		 sc_dev;
 	bus_space_tag_t		 sc_bst;
 	bus_space_handle_t	 sc_bsh;
-	uint32_t		 sc_irq;
+	int			 sc_phandle;
 
 	uint32_t		 sc_freq;
 	void			*sc_global_ih;
@@ -48,8 +48,7 @@ static struct mct_softc {
 	uint64_t		 sc_lastintr;
 	uint32_t		 sc_autoinc;
 	struct evcnt		 sc_ev_missing_ticks;
-
-} mct_sc;
+};
 
 void mct_init_cpu_clock(struct cpu_info *ci);
 void mct_delay(u_int);

Reply via email to