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);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to