Module Name:    src
Committed By:   jmcneill
Date:           Sat Apr 22 17:40:47 UTC 2017

Modified Files:
        src/sys/arch/arm/nvidia: tegra124_car.c

Log Message:
Fix fractional divider calculations and round down for sdmmc clocks.


To generate a diff of this commit:
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/nvidia/tegra124_car.c

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/nvidia/tegra124_car.c
diff -u src/sys/arch/arm/nvidia/tegra124_car.c:1.10 src/sys/arch/arm/nvidia/tegra124_car.c:1.11
--- src/sys/arch/arm/nvidia/tegra124_car.c:1.10	Sun Apr 16 12:28:21 2017
+++ src/sys/arch/arm/nvidia/tegra124_car.c	Sat Apr 22 17:40:47 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra124_car.c,v 1.10 2017/04/16 12:28:21 jmcneill Exp $ */
+/* $NetBSD: tegra124_car.c,v 1.11 2017/04/22 17:40:47 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <[email protected]>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra124_car.c,v 1.10 2017/04/16 12:28:21 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra124_car.c,v 1.11 2017/04/22 17:40:47 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -1204,6 +1204,16 @@ tegra124_car_clock_get_rate_fixed_div(st
 }
 
 static u_int
+tegra124_car_clock_calc_rate_frac_div(u_int rate, u_int raw_div)
+{
+	raw_div += 2;
+	rate *= 2;
+	rate += raw_div - 1;
+	rate /= raw_div;
+	return rate;
+}
+
+static u_int
 tegra124_car_clock_get_rate_div(struct tegra124_car_softc *sc,
     struct tegra_clk *tclk)
 {
@@ -1235,13 +1245,15 @@ tegra124_car_clock_get_rate_div(struct t
 	case CAR_CLKSRC_UARTC_REG:
 	case CAR_CLKSRC_UARTD_REG:
 		if (v & CAR_CLKSRC_UART_DIV_ENB) {
-			rate = parent_rate * 2 / (raw_div + 2);
+			rate = tegra124_car_clock_calc_rate_frac_div(
+			    parent_rate, raw_div);
 		} else {
 			rate = parent_rate;
 		}
 		break;
 	default:
-		rate = parent_rate * 2 / (raw_div + 2);
+		rate = tegra124_car_clock_calc_rate_frac_div(parent_rate,
+		    raw_div);
 		break;
 	}
 
@@ -1301,6 +1313,22 @@ tegra124_car_clock_set_rate_div(struct t
 		if (rate)
 			raw_div = parent_rate / rate - 1;
 		break;
+	case CAR_CLKSRC_SDMMC1_REG:
+	case CAR_CLKSRC_SDMMC2_REG:
+	case CAR_CLKSRC_SDMMC3_REG:
+	case CAR_CLKSRC_SDMMC4_REG:
+		if (rate) {
+			for (raw_div = 0x00; raw_div <= 0xff; raw_div++) {
+				u_int calc_rate =
+				    tegra124_car_clock_calc_rate_frac_div(
+					parent_rate, raw_div);
+				if (calc_rate <= rate)
+					break;
+			}
+			if (raw_div == 0x100)
+				return EINVAL;
+		}
+		break;
 	default:
 		if (rate)
 			raw_div = (parent_rate * 2) / rate - 2;

Reply via email to