Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/arm/nvidia Tegra K1 CPU frequency scaling support.



details:   https://anonhg.NetBSD.org/src/rev/7b1860b7936a
branches:  trunk
changeset: 338175:7b1860b7936a
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Wed May 13 11:06:13 2015 +0000

description:
Tegra K1 CPU frequency scaling support.

jetsontk1# sysctl machdep.cpu
machdep.cpu.frequency.target = 2292
machdep.cpu.frequency.current = 2292
machdep.cpu.frequency.available = 2292 2100 1896 1692 1500 1296 1092 900 696

diffstat:

 sys/arch/arm/nvidia/files.tegra     |    6 +-
 sys/arch/arm/nvidia/soc_tegra124.c  |   78 ++++++++++++++-
 sys/arch/arm/nvidia/tegra_car.c     |   49 ++++++++-
 sys/arch/arm/nvidia/tegra_carreg.h  |   14 ++-
 sys/arch/arm/nvidia/tegra_cpufreq.c |  185 ++++++++++++++++++++++++++++++++++++
 sys/arch/arm/nvidia/tegra_soc.c     |   18 +++-
 sys/arch/arm/nvidia/tegra_var.h     |   14 ++-
 7 files changed, 354 insertions(+), 10 deletions(-)

diffs (truncated from 507 to 300 lines):

diff -r de6b13ff3591 -r 7b1860b7936a sys/arch/arm/nvidia/files.tegra
--- a/sys/arch/arm/nvidia/files.tegra   Wed May 13 10:49:26 2015 +0000
+++ b/sys/arch/arm/nvidia/files.tegra   Wed May 13 11:06:13 2015 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.tegra,v 1.9 2015/05/10 23:50:21 jmcneill Exp $
+#      $NetBSD: files.tegra,v 1.10 2015/05/13 11:06:13 jmcneill Exp $
 #
 # Configuration info for NVIDIA Tegra ARM Peripherals
 #
@@ -14,6 +14,7 @@
 file   arch/arm/arm/bus_space_a4x.S
 
 file   arch/arm/nvidia/tegra_soc.c
+file   arch/arm/nvidia/tegra_cpufreq.c
 file   arch/arm/nvidia/soc_tegra124.c          soc_tegra124
 
 # On-board I/O
@@ -89,6 +90,9 @@
 # Memory parameters
 defparam opt_tegra.h                   MEMSIZE
 
+# CPU parameters
+defparam opt_tegra.h                   CPUFREQ_BOOT
+
 # SOC parameters
 defflag        opt_tegra.h                     SOC_TEGRAK1
 defflag        opt_tegra.h                     SOC_TEGRA124: SOC_TEGRAK1
diff -r de6b13ff3591 -r 7b1860b7936a sys/arch/arm/nvidia/soc_tegra124.c
--- a/sys/arch/arm/nvidia/soc_tegra124.c        Wed May 13 10:49:26 2015 +0000
+++ b/sys/arch/arm/nvidia/soc_tegra124.c        Wed May 13 11:06:13 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: soc_tegra124.c,v 1.2 2015/04/26 22:04:28 jmcneill Exp $ */
+/* $NetBSD: soc_tegra124.c,v 1.3 2015/05/13 11:06:13 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -30,7 +30,7 @@
 #include "opt_multiprocessor.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: soc_tegra124.c,v 1.2 2015/04/26 22:04:28 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: soc_tegra124.c,v 1.3 2015/05/13 11:06:13 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -47,6 +47,80 @@
 
 #define EVP_RESET_VECTOR_0_REG 0x100
 
+static u_int   tegra124_cpufreq_set_rate(u_int);
+static u_int   tegra124_cpufreq_get_rate(void);
+static size_t  tegra124_cpufreq_get_available(u_int *, size_t);
+
+static const struct tegra_cpufreq_func tegra124_cpufreq_func = {
+       .set_rate = tegra124_cpufreq_set_rate,
+       .get_rate = tegra124_cpufreq_get_rate,
+       .get_available = tegra124_cpufreq_get_available,
+};
+
+static struct tegra124_cpufreq_rate {
+       u_int rate;
+       u_int divm;
+       u_int divn;
+       u_int divp;
+} tegra124_cpufreq_rates[] = {
+       { 2292, 1, 191, 0 },
+       { 2100, 1, 175, 0 },
+       { 1896, 1, 158, 0 },
+       { 1692, 1, 141, 0 },
+       { 1500, 1, 125, 0 },
+       { 1296, 1, 108, 0 },
+       { 1092, 1, 91, 0 },
+       { 900, 1, 75, 0 },
+       { 696, 1, 58, 0 }
+};
+
+void
+tegra124_cpuinit(void)
+{
+       tegra_cpufreq_register(&tegra124_cpufreq_func);
+}
+
+static u_int
+tegra124_cpufreq_set_rate(u_int rate)
+{
+       const u_int nrates = __arraycount(tegra124_cpufreq_rates);
+       const struct tegra124_cpufreq_rate *r = NULL;
+
+       for (int i = 0; i < nrates; i++) {
+               if (tegra124_cpufreq_rates[i].rate == rate) {
+                       r = &tegra124_cpufreq_rates[i];
+                       break;
+               }
+       }
+       if (r == NULL)
+               return EINVAL;
+
+       tegra_car_pllx_set_rate(r->divm, r->divn, r->divp);
+
+       return 0;
+}
+
+static u_int
+tegra124_cpufreq_get_rate(void)
+{
+       return tegra_car_pllx_rate() / 1000000;
+}
+
+static size_t
+tegra124_cpufreq_get_available(u_int *pavail, size_t maxavail)
+{
+       const u_int nrates = __arraycount(tegra124_cpufreq_rates);
+       u_int n;
+
+       KASSERT(nrates <= maxavail);
+
+       for (n = 0; n < nrates; n++) {
+               pavail[n] = tegra124_cpufreq_rates[n].rate;
+       }
+
+       return nrates;
+}
+
 void
 tegra124_mpinit(void)
 {
diff -r de6b13ff3591 -r 7b1860b7936a sys/arch/arm/nvidia/tegra_car.c
--- a/sys/arch/arm/nvidia/tegra_car.c   Wed May 13 10:49:26 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_car.c   Wed May 13 11:06:13 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_car.c,v 1.10 2015/05/10 23:56:21 jmcneill Exp $ */
+/* $NetBSD: tegra_car.c,v 1.11 2015/05/13 11:06:13 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -29,7 +29,7 @@
 #include "locators.h"
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.10 2015/05/10 23:56:21 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tegra_car.c,v 1.11 2015/05/13 11:06:13 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/bus.h>
@@ -117,7 +117,6 @@
 
        tegra_car_get_bs(&bst, &bsh);
 
-       rate = tegra_car_osc_rate();    
        const uint32_t base = bus_space_read_4(bst, bsh, base_reg);
        const u_int divm = __SHIFTOUT(base, divm_mask);
        const u_int divn = __SHIFTOUT(base, divn_mask);
@@ -128,6 +127,50 @@
        return rate / (divm << divp);
 }
 
+void
+tegra_car_pllx_set_rate(u_int divm, u_int divn, u_int divp)
+{
+       bus_space_tag_t bst;
+       bus_space_handle_t bsh;
+       uint32_t base, bp;
+
+       tegra_car_get_bs(&bst, &bsh);
+
+       bp = bus_space_read_4(bst, bsh, CAR_CCLKG_BURST_POLICY_REG);
+       bp &= ~CAR_CCLKG_BURST_POLICY_CPU_STATE;
+       bp |= __SHIFTIN(CAR_CCLKG_BURST_POLICY_CPU_STATE_IDLE,
+                       CAR_CCLKG_BURST_POLICY_CPU_STATE);
+       bp &= ~CAR_CCLKG_BURST_POLICY_CWAKEUP_IDLE_SOURCE;
+       bp |= __SHIFTIN(CAR_CCLKG_BURST_POLICY_CWAKEUP_SOURCE_CLKM,
+                       CAR_CCLKG_BURST_POLICY_CWAKEUP_IDLE_SOURCE);
+       bus_space_write_4(bst, bsh, CAR_CCLKG_BURST_POLICY_REG, bp);
+
+       base = bus_space_read_4(bst, bsh, CAR_PLLX_BASE_REG);
+       base &= ~CAR_PLLX_BASE_DIVM;
+       base &= ~CAR_PLLX_BASE_DIVN;
+       base &= ~CAR_PLLX_BASE_DIVP;
+       base |= __SHIFTIN(divm, CAR_PLLX_BASE_DIVM);
+       base |= __SHIFTIN(divn, CAR_PLLX_BASE_DIVN);
+       base |= __SHIFTIN(divp, CAR_PLLX_BASE_DIVP);
+       bus_space_write_4(bst, bsh, CAR_PLLX_BASE_REG, base);
+
+       tegra_reg_set_clear(bst, bsh, CAR_PLLX_MISC_REG,
+           CAR_PLLX_MISC_LOCK_ENABLE, 0);
+       do {
+               delay(2);
+               base = bus_space_read_4(bst, bsh, CAR_PLLX_BASE_REG);
+       } while ((base & CAR_PLLX_BASE_LOCK) == 0);
+       delay(100);
+
+       bp &= ~CAR_CCLKG_BURST_POLICY_CPU_STATE;
+       bp |= __SHIFTIN(CAR_CCLKG_BURST_POLICY_CPU_STATE_RUN,
+                       CAR_CCLKG_BURST_POLICY_CPU_STATE);
+       bp &= ~CAR_CCLKG_BURST_POLICY_CWAKEUP_IDLE_SOURCE;
+       bp |= __SHIFTIN(CAR_CCLKG_BURST_POLICY_CWAKEUP_SOURCE_PLLX_OUT0_LJ,
+                       CAR_CCLKG_BURST_POLICY_CWAKEUP_IDLE_SOURCE);
+       bus_space_write_4(bst, bsh, CAR_CCLKG_BURST_POLICY_REG, bp);
+}
+
 u_int
 tegra_car_pllx_rate(void)
 {
diff -r de6b13ff3591 -r 7b1860b7936a sys/arch/arm/nvidia/tegra_carreg.h
--- a/sys/arch/arm/nvidia/tegra_carreg.h        Wed May 13 10:49:26 2015 +0000
+++ b/sys/arch/arm/nvidia/tegra_carreg.h        Wed May 13 11:06:13 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tegra_carreg.h,v 1.11 2015/05/10 23:50:21 jmcneill Exp $ */
+/* $NetBSD: tegra_carreg.h,v 1.12 2015/05/13 11:06:13 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -88,6 +88,10 @@
 #define CAR_PLLX_BASE_DIVM             __BITS(7,0)
 
 #define CAR_PLLX_MISC_REG      0xe4
+#define CAR_PLLX_MISC_FO_LP_DISABLE    __BIT(29)
+#define CAR_PLLX_MISC_FO_G_DISABLE     __BIT(28)
+#define CAR_PLLX_MISC_PTS              __BITS(23,22)
+#define CAR_PLLX_MISC_LOCK_ENABLE      __BIT(18)
 
 #define CAR_PLLE_BASE_REG      0xe8
 #define CAR_PLLE_BASE_ENABLE           __BIT(30)
@@ -296,6 +300,14 @@
 #define CAR_DEV_X_CAM_MCLK             __BIT(4)
 #define CAR_DEV_X_SPARE                        __BIT(0)
 
+#define CAR_CCLKG_BURST_POLICY_REG     0x368
+#define CAR_CCLKG_BURST_POLICY_CPU_STATE       __BITS(31,28)
+#define CAR_CCLKG_BURST_POLICY_CPU_STATE_IDLE                  1
+#define CAR_CCLKG_BURST_POLICY_CPU_STATE_RUN                   2
+#define CAR_CCLKG_BURST_POLICY_CWAKEUP_IDLE_SOURCE __BITS(3,0)
+#define CAR_CCLKG_BURST_POLICY_CWAKEUP_SOURCE_CLKM             0
+#define CAR_CCLKG_BURST_POLICY_CWAKEUP_SOURCE_PLLX_OUT0_LJ     8
+
 #define CAR_UTMIP_PLL_CFG0_REG         0x480
 
 #define CAR_UTMIP_PLL_CFG1_REG         0x484
diff -r de6b13ff3591 -r 7b1860b7936a sys/arch/arm/nvidia/tegra_cpufreq.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/nvidia/tegra_cpufreq.c       Wed May 13 11:06:13 2015 +0000
@@ -0,0 +1,185 @@
+/* $NetBSD: tegra_cpufreq.c,v 1.1 2015/05/13 11:06:13 jmcneill Exp $ */
+
+/*-
+ * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "locators.h"
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: tegra_cpufreq.c,v 1.1 2015/05/13 11:06:13 jmcneill Exp $");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/intr.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/atomic.h>
+#include <sys/kmem.h>
+#include <sys/xcall.h>
+#include <sys/sysctl.h>
+
+#include <arm/nvidia/tegra_var.h>
+
+static u_int cpufreq_busy;
+static struct sysctllog *cpufreq_log;
+static int cpufreq_node_target, cpufreq_node_current, cpufreq_node_available;
+
+static const struct tegra_cpufreq_func *cpufreq_func = NULL;
+
+static void    tegra_cpufreq_post(void *, void *);
+static int     tegra_cpufreq_freq_helper(SYSCTLFN_PROTO);
+static char    tegra_cpufreq_available[TEGRA_CPUFREQ_MAX * 5];
+
+#define cpufreq_set_rate       cpufreq_func->set_rate
+#define cpufreq_get_rate       cpufreq_func->get_rate



Home | Main Index | Thread Index | Old Index