svn commit: r333716 - head/sys/arm/allwinner

Emmanuel Vadot manu at FreeBSD.org
Thu May 17 14:51:23 UTC 2018


Author: manu
Date: Thu May 17 14:51:22 2018
New Revision: 333716
URL: https://svnweb.freebsd.org/changeset/base/333716

Log:
  aw_spi: Fix some silly clock mistake
  
  The module uses the mod clock and not the ahb one.
  We need to set the mod clock to twice the speed requested as the smallest
  divider in the controller is 2.
  The clock test function weren't calculating the register value best on the
  best div but on the max one.
  The cdr2 test function was using the cdr1 formula.
  
  Pointy Hat: manu

Modified:
  head/sys/arm/allwinner/aw_spi.c

Modified: head/sys/arm/allwinner/aw_spi.c
==============================================================================
--- head/sys/arm/allwinner/aw_spi.c	Thu May 17 14:38:58 2018	(r333715)
+++ head/sys/arm/allwinner/aw_spi.c	Thu May 17 14:51:22 2018	(r333716)
@@ -143,7 +143,7 @@ struct aw_spi_softc {
 	struct mtx	mtx;
 	clk_t		clk_ahb;
 	clk_t		clk_mod;
-	uint64_t	ahb_freq;
+	uint64_t	mod_freq;
 	hwreset_t	rst_ahb;
 	void *		intrhand;
 	int		transfer;
@@ -238,8 +238,6 @@ aw_spi_attach(device_t dev)
 		goto fail;
 	}
 
-	clk_get_freq(sc->clk_ahb, &sc->ahb_freq);
-
 	sc->spibus = device_add_child(dev, "spibus", -1);
 
 	return (0);
@@ -329,33 +327,33 @@ aw_spi_clock_test_cdr1(struct aw_spi_softc *sc, uint64
 
 	max = AW_SPI_CCR_CDR1_MASK >> AW_SPI_CCR_CDR1_SHIFT;
 	for (i = 0; i < max; i++) {
-		cur = sc->ahb_freq / (1 << i);
+		cur = sc->mod_freq / (1 << i);
 		if ((clock - cur) < (clock - best)) {
 			best = cur;
 			best_div = i;
 		}
 	}
 
-	*ccr = (i << AW_SPI_CCR_CDR1_SHIFT);
+	*ccr = (best_div << AW_SPI_CCR_CDR1_SHIFT);
 	return (best);
 }
 
 static uint64_t
-aw_spi_clock_test_cdr2(struct aw_spi_softc *sc, uint32_t clock, uint32_t *ccr)
+aw_spi_clock_test_cdr2(struct aw_spi_softc *sc, uint64_t clock, uint32_t *ccr)
 {
 	uint64_t cur, best = 0;
 	int i, max, best_div;
 
 	max = ((AW_SPI_CCR_CDR2_MASK) >> AW_SPI_CCR_CDR2_SHIFT);
 	for (i = 0; i < max; i++) {
-		cur = sc->ahb_freq / (1 << i);
+		cur = sc->mod_freq / (2 * i + 1);
 		if ((clock - cur) < (clock - best)) {
 			best = cur;
 			best_div = i;
 		}
 	}
 
-	*ccr = AW_SPI_CCR_DRS | (i << AW_SPI_CCR_CDR2_SHIFT);
+	*ccr = AW_SPI_CCR_DRS | (best_div << AW_SPI_CCR_CDR2_SHIFT);
 	return (best);
 }
 
@@ -531,6 +529,9 @@ aw_spi_transfer(device_t dev, device_t child, struct s
 	spibus_get_clock(child, &clock);
 	spibus_get_mode(child, &mode);
 
+	/* The minimum divider is 2 so set the clock at twice the needed speed */
+	clk_set_freq(sc->clk_mod, 2 * clock, CLK_SET_ROUND_DOWN);
+	clk_get_freq(sc->clk_mod, &sc->mod_freq);
 	if (cs >= AW_SPI_MAX_CS) {
 		device_printf(dev, "Invalid cs %d\n", cs);
 		return (EINVAL);


More information about the svn-src-head mailing list