Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 15 May 2014 22:50:06 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r266201 - in stable/10/sys: arm/arm arm/conf arm/freescale/imx arm/freescale/vybrid arm/include boot/fdt/dts
Message-ID:  <201405152250.s4FMo6tG051305@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ian
Date: Thu May 15 22:50:06 2014
New Revision: 266201
URL: http://svnweb.freebsd.org/changeset/base/266201

Log:
  MFC r261982, r261987, r262123, r262244, r262278, r262280, r262353, r262354,
      r262355, r262419,
  
    Add Vybrid driver for Synchronous Audio Interface (SAI).
  
    Decrease SAI buffer size. Handle eDMA interrupt on running channel only.
  
    Give the physmem fdt helper routines static linkage since no global
    definition of them is provided anywhere.
  
    Add imx6 early printf support, wrapped in #if 0 because it's rarely needed.
  
    Add basic cpu frequency control and temperature monitoring to imx6_anatop.
  
    Add the FREEBSD_BOOT_LOADER option so that a loaded DTB passed in from
    ubldr will actually get used.
  
    Create a generic IMX6 kernel config, then fix it to have an ident line.
  
    Don't force imx6 bootverbose on anymore, it can be set from ubldr now.

Added:
  stable/10/sys/arm/conf/IMX6
     - copied, changed from r262354, head/sys/arm/conf/IMX6
  stable/10/sys/arm/freescale/vybrid/vf_sai.c
     - copied, changed from r261982, head/sys/arm/freescale/vybrid/vf_sai.c
Modified:
  stable/10/sys/arm/arm/machdep.c
  stable/10/sys/arm/conf/WANDBOARD.common
  stable/10/sys/arm/freescale/imx/imx6_anatop.c
  stable/10/sys/arm/freescale/imx/imx6_anatopreg.h
  stable/10/sys/arm/freescale/imx/imx6_anatopvar.h
  stable/10/sys/arm/freescale/imx/imx6_machdep.c
  stable/10/sys/arm/freescale/vybrid/files.vybrid
  stable/10/sys/arm/include/physmem.h
  stable/10/sys/boot/fdt/dts/imx6.dtsi
  stable/10/sys/boot/fdt/dts/vybrid.dtsi
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/arm/arm/machdep.c
==============================================================================
--- stable/10/sys/arm/arm/machdep.c	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/arm/machdep.c	Thu May 15 22:50:06 2014	(r266201)
@@ -1167,7 +1167,6 @@ initarm(struct arm_boot_params *abp)
 	   (((uint32_t)(lastaddr) - KERNVIRTADDR) + PAGE_MASK) & ~PAGE_MASK,
 	    VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
 
-
 	/* Map L1 directory and allocated L2 page tables */
 	pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
 	    L1_TABLE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);

Copied and modified: stable/10/sys/arm/conf/IMX6 (from r262354, head/sys/arm/conf/IMX6)
==============================================================================
--- head/sys/arm/conf/IMX6	Sun Feb 23 01:48:07 2014	(r262354, copy source)
+++ stable/10/sys/arm/conf/IMX6	Thu May 15 22:50:06 2014	(r266201)
@@ -17,6 +17,7 @@
 #
 # $FreeBSD$
 
+ident		IMX6
 include 	"../freescale/imx/std.imx6"
 
 options  	HZ=250			# Scheduling quantum is 4 milliseconds.

Modified: stable/10/sys/arm/conf/WANDBOARD.common
==============================================================================
--- stable/10/sys/arm/conf/WANDBOARD.common	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/conf/WANDBOARD.common	Thu May 15 22:50:06 2014	(r266201)
@@ -153,3 +153,5 @@ device  	mmcsd		# SDCard disk device
 
 device  	ffec		# Freescale Fast Ethernet Controller
 
+options  	FREEBSD_BOOT_LOADER	# Process metadata passed from loader(8)
+

Modified: stable/10/sys/arm/freescale/imx/imx6_anatop.c
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatop.c	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/freescale/imx/imx6_anatop.c	Thu May 15 22:50:06 2014	(r266201)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2013 Ian Lepore <ian@freebsd.org>
+ * Copyright (c) 2014 Steven Lawrance <stl@koffein.net>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,6 +30,8 @@ __FBSDID("$FreeBSD$");
 
 /*
  * Analog PLL and power regulator driver for Freescale i.MX6 family of SoCs.
+ * Also, temperature montoring and cpu frequency control.  It was Freescale who
+ * kitchen-sinked this device, not us. :)
  *
  * We don't really do anything with analog PLLs, but the registers for
  * controlling them belong to the same block as the power regulator registers.
@@ -42,11 +45,19 @@ __FBSDID("$FreeBSD$");
  * I have no idea where the "anatop" name comes from.  It's in the standard DTS
  * source describing i.MX6 SoCs, and in the linux and u-boot code which comes
  * from Freescale, but it's not in the SoC manual.
+ *
+ * Note that temperature values throughout this code are handled in two types of
+ * units.  Items with '_cnt' in the name use the hardware temperature count
+ * units (higher counts are lower temperatures).  Items with '_val' in the name
+ * are deci-Celcius, which are converted to/from deci-Kelvins in the sysctl
+ * handlers (dK is the standard unit for temperature in sysctl).
  */
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/callout.h>
 #include <sys/kernel.h>
+#include <sys/sysctl.h>
 #include <sys/module.h>
 #include <sys/bus.h>
 #include <sys/rman.h>
@@ -56,68 +67,410 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/bus.h>
 
+#include <arm/freescale/fsl_ocotpreg.h>
+#include <arm/freescale/fsl_ocotpvar.h>
 #include <arm/freescale/imx/imx6_anatopreg.h>
 #include <arm/freescale/imx/imx6_anatopvar.h>
 
+static struct resource_spec imx6_anatop_spec[] = {
+	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
+	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
+	{ -1, 0 }
+};
+#define	MEMRES	0
+#define	IRQRES	1
+
 struct imx6_anatop_softc {
 	device_t	dev;
-	struct resource	*mem_res;
+	struct resource	*res[2];
+	uint32_t	cpu_curhz;
+	uint32_t	cpu_curmhz;
+	uint32_t	cpu_minhz;
+	uint32_t	cpu_maxhz;
+	uint32_t	refosc_hz;
+	void		*temp_intrhand;
+	uint32_t	temp_high_val;
+	uint32_t	temp_high_cnt;
+	uint32_t	temp_last_cnt;
+	uint32_t	temp_room_cnt;
+	struct callout	temp_throttle_callout;
+	sbintime_t	temp_throttle_delay;
+	uint32_t	temp_throttle_reset_cnt;
+	uint32_t	temp_throttle_trigger_cnt;
+	uint32_t	temp_throttle_val;
 };
 
 static struct imx6_anatop_softc *imx6_anatop_sc;
 
+/*
+ * Table of CPU max frequencies.  This is indexed by the max frequency value
+ * (0-3) from the ocotp CFG3 register.
+ */
+static uint32_t imx6_cpu_maxhz_tab[] = {
+	 792000000, 852000000, 996000000, 1200000000
+};
+
+#define	TZ_ZEROC	2732	/* deci-Kelvin <-> deci-Celcius offset. */
+
 uint32_t
 imx6_anatop_read_4(bus_size_t offset)
 {
 
-	return (bus_read_4(imx6_anatop_sc->mem_res, offset));
+	KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_read_4 sc NULL"));
+
+	return (bus_read_4(imx6_anatop_sc->res[MEMRES], offset));
 }
 
 void
 imx6_anatop_write_4(bus_size_t offset, uint32_t value)
 {
 
-	bus_write_4(imx6_anatop_sc->mem_res, offset, value);
+	KASSERT(imx6_anatop_sc != NULL, ("imx6_anatop_write_4 sc NULL"));
+
+	bus_write_4(imx6_anatop_sc->res[MEMRES], offset, value);
+}
+
+static inline uint32_t
+cpufreq_hz_from_div(struct imx6_anatop_softc *sc, uint32_t div)
+{
+
+	return (sc->refosc_hz * (div / 2));
+}
+
+static inline uint32_t
+cpufreq_hz_to_div(struct imx6_anatop_softc *sc, uint32_t cpu_hz)
+{
+
+	return (cpu_hz / (sc->refosc_hz / 2));
+}
+
+static inline uint32_t
+cpufreq_actual_hz(struct imx6_anatop_softc *sc, uint32_t cpu_hz)
+{
+
+	return (cpufreq_hz_from_div(sc, cpufreq_hz_to_div(sc, cpu_hz)));
+}
+
+static void 
+cpufreq_set_clock(struct imx6_anatop_softc * sc, uint32_t cpu_newhz)
+{
+	uint32_t div, timeout, wrk32;
+	const uint32_t mindiv =  54;
+	const uint32_t maxdiv = 108;
+
+	/*
+	 * Clip the requested frequency to the configured max, then clip the
+	 * resulting divisor to the documented min/max values.
+	 */
+	cpu_newhz = min(cpu_newhz, sc->cpu_maxhz);
+	div = cpufreq_hz_to_div(sc, cpu_newhz);
+	if (div < mindiv)
+		div = mindiv;
+	else if (div > maxdiv)
+		div = maxdiv;
+	sc->cpu_curhz = cpufreq_hz_from_div(sc, div);
+	sc->cpu_curmhz = sc->cpu_curhz / 1000000;
+
+	/*
+	 * I can't find a documented procedure for changing the ARM PLL divisor,
+	 * but some trial and error came up with this:
+	 *  - Set the bypass clock source to REF_CLK_24M (source #0).
+	 *  - Set the PLL into bypass mode; cpu should now be running at 24mhz.
+	 *  - Change the divisor.
+	 *  - Wait for the LOCK bit to come on; it takes ~50 loop iterations.
+	 *  - Turn off bypass mode; cpu should now be running at cpu_newhz.
+	 */
+	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 
+	    IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK);
+	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_SET, 
+	    IMX6_ANALOG_CCM_PLL_ARM_BYPASS);
+
+	wrk32 = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM);
+	wrk32 &= ~IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK;
+	wrk32 |= div;
+	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM, wrk32);
+
+	timeout = 10000;
+	while ((imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) &
+	    IMX6_ANALOG_CCM_PLL_ARM_LOCK) == 0)
+		if (--timeout == 0)
+			panic("imx6_set_cpu_clock(): PLL never locked");
+
+	imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_ARM_CLR, 
+	    IMX6_ANALOG_CCM_PLL_ARM_BYPASS);
+}
+
+static void
+cpufreq_initialize(struct imx6_anatop_softc *sc)
+{
+	uint32_t cfg3speed;
+	struct sysctl_ctx_list *ctx;
+
+	ctx = device_get_sysctl_ctx(sc->dev);
+	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
+	    OID_AUTO, "cpu_mhz", CTLFLAG_RD, &sc->cpu_curmhz, 0, 
+	    "CPU frequency in MHz");
+
+	/*
+	 * XXX 24mhz shouldn't be hard-coded, should get this from imx6_ccm
+	 * (even though in the real world it will always be 24mhz).  Oh wait a
+	 * sec, I never wrote imx6_ccm.
+	 */
+	sc->refosc_hz = 24000000;
+
+	/*
+	 * Get the maximum speed this cpu can be set to.  The values in the
+	 * OCOTP CFG3 register are not documented in the reference manual.
+	 * The following info was in an archived email found via web search:
+	 *   - 2b'11: 1200000000Hz;
+	 *   - 2b'10: 996000000Hz;
+	 *   - 2b'01: 852000000Hz; -- i.MX6Q Only, exclusive with 996MHz.
+	 *   - 2b'00: 792000000Hz;
+	 */
+	cfg3speed = (fsl_ocotp_read_4(FSL_OCOTP_CFG3) & 
+	    FSL_OCOTP_CFG3_SPEED_MASK) >> FSL_OCOTP_CFG3_SPEED_SHIFT;
+
+	sc->cpu_minhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[0]);
+	sc->cpu_maxhz = cpufreq_actual_hz(sc, imx6_cpu_maxhz_tab[cfg3speed]);
+
+	/*
+	 * Set the CPU to maximum speed.
+	 *
+	 * We won't have thermal throttling until interrupts are enabled, but we
+	 * want to run at full speed through all the device init stuff.  This
+	 * basically assumes that a single core can't overheat before interrupts
+	 * are enabled; empirical testing shows that to be a safe assumption.
+	 */
+	cpufreq_set_clock(sc, sc->cpu_maxhz);
+	device_printf(sc->dev, "CPU frequency %uMHz\n", sc->cpu_curmhz);
+}
+
+static inline uint32_t
+temp_from_count(struct imx6_anatop_softc *sc, uint32_t count)
+{
+
+	return (((sc->temp_high_val - (count - sc->temp_high_cnt) *
+	    (sc->temp_high_val - 250) / 
+	    (sc->temp_room_cnt - sc->temp_high_cnt))));
+}
+
+static inline uint32_t
+temp_to_count(struct imx6_anatop_softc *sc, uint32_t temp)
+{
+
+	return ((sc->temp_room_cnt - sc->temp_high_cnt) * 
+	    (sc->temp_high_val - temp) / (sc->temp_high_val - 250) + 
+	    sc->temp_high_cnt);
+}
+
+static void
+temp_update_count(struct imx6_anatop_softc *sc)
+{
+	uint32_t val;
+
+	val = imx6_anatop_read_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0);
+	if (!(val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID))
+		return;
+	sc->temp_last_cnt =
+	    (val & IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK) >>
+	    IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT;
 }
 
 static int
-imx6_anatop_detach(device_t dev)
+temp_sysctl_handler(SYSCTL_HANDLER_ARGS)
 {
-	struct imx6_anatop_softc *sc;
+	struct imx6_anatop_softc *sc = arg1;
+	uint32_t t;
 
-	sc = device_get_softc(dev);
+	temp_update_count(sc);
 
-	if (sc->mem_res != NULL)
-		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
+	t = temp_from_count(sc, sc->temp_last_cnt) + TZ_ZEROC;
 
-	return (0);
+	return (sysctl_handle_int(oidp, &t, 0, req));
+}
+
+static int
+temp_throttle_sysctl_handler(SYSCTL_HANDLER_ARGS)
+{
+	struct imx6_anatop_softc *sc = arg1;
+	int err;
+	uint32_t temp;
+
+	temp = sc->temp_throttle_val + TZ_ZEROC;
+	err = sysctl_handle_int(oidp, &temp, 0, req);
+	if (temp < TZ_ZEROC)
+		return (ERANGE);
+	temp -= TZ_ZEROC;
+	if (err != 0 || req->newptr == NULL || temp == sc->temp_throttle_val)
+		return (err);
+
+	/* Value changed, update counts in softc and hardware. */
+	sc->temp_throttle_val = temp;
+	sc->temp_throttle_trigger_cnt = temp_to_count(sc, sc->temp_throttle_val);
+	sc->temp_throttle_reset_cnt = temp_to_count(sc, sc->temp_throttle_val - 100);
+	imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR,
+	    IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK);
+	imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET,
+	    (sc->temp_throttle_trigger_cnt <<
+	     IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT));
+	return (err);
+}
+
+static void
+tempmon_gofast(struct imx6_anatop_softc *sc)
+{
+
+	if (sc->cpu_curhz < sc->cpu_maxhz) {
+		cpufreq_set_clock(sc, sc->cpu_maxhz);
+	}
+}
+
+static void
+tempmon_goslow(struct imx6_anatop_softc *sc)
+{
+
+	if (sc->cpu_curhz > sc->cpu_minhz) {
+		cpufreq_set_clock(sc, sc->cpu_minhz);
+	}
+}
+
+static int
+tempmon_intr(void *arg)
+{
+	struct imx6_anatop_softc *sc = arg;
+
+	/*
+	 * XXX Note that this code doesn't currently run (for some mysterious
+	 * reason we just never get an interrupt), so the real monitoring is
+	 * done by tempmon_throttle_check().
+	 */
+	tempmon_goslow(sc);
+	/* XXX Schedule callout to speed back up eventually. */
+	return (FILTER_HANDLED);
+}
+
+static void
+tempmon_throttle_check(void *arg)
+{
+	struct imx6_anatop_softc *sc = arg;
+
+	/* Lower counts are higher temperatures. */
+	if (sc->temp_last_cnt < sc->temp_throttle_trigger_cnt)
+		tempmon_goslow(sc);
+	else if (sc->temp_last_cnt > (sc->temp_throttle_reset_cnt))
+		tempmon_gofast(sc);
+
+	callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay,
+		0, tempmon_throttle_check, sc, 0);
+
+}
+
+static void
+initialize_tempmon(struct imx6_anatop_softc *sc)
+{
+	uint32_t cal;
+	struct sysctl_ctx_list *ctx;
+
+	/*
+	 * Fetch calibration data: a sensor count at room temperature (25C),
+	 * a sensor count at a high temperature, and that temperature
+	 */
+	cal = fsl_ocotp_read_4(FSL_OCOTP_ANA1);
+	sc->temp_room_cnt = (cal & 0xFFF00000) >> 20;
+	sc->temp_high_cnt = (cal & 0x000FFF00) >> 8;
+	sc->temp_high_val = (cal & 0x000000FF) * 10;
+
+	/*
+	 * Throttle to a lower cpu freq at 10C below the "hot" temperature, and
+	 * reset back to max cpu freq at 5C below the trigger.
+	 */
+	sc->temp_throttle_val = sc->temp_high_val - 100;
+	sc->temp_throttle_trigger_cnt =
+	    temp_to_count(sc, sc->temp_throttle_val);
+	sc->temp_throttle_reset_cnt = 
+	    temp_to_count(sc, sc->temp_throttle_val - 50);
+
+	/*
+	 * Set the sensor to sample automatically at 16Hz (32.768KHz/0x800), set
+	 * the throttle count, and begin making measurements.
+	 */
+	imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE1, 0x0800);
+	imx6_anatop_write_4(IMX6_ANALOG_TEMPMON_TEMPSENSE0,
+	    (sc->temp_throttle_trigger_cnt << 
+	    IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT) |
+	    IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE);
+
+	/*
+	 * XXX Note that the alarm-interrupt feature isn't working yet, so
+	 * we'll use a callout handler to check at 10Hz.  Make sure we have an
+	 * initial temperature reading before starting up the callouts so we
+	 * don't get a bogus reading of zero.
+	 */
+	while (sc->temp_last_cnt == 0)
+		temp_update_count(sc);
+	sc->temp_throttle_delay = 100 * SBT_1MS;
+	callout_init(&sc->temp_throttle_callout, 0);
+	callout_reset_sbt(&sc->temp_throttle_callout, sc->temp_throttle_delay, 
+	    0, tempmon_throttle_check, sc, 0);
+
+	ctx = device_get_sysctl_ctx(sc->dev);
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
+	    OID_AUTO, "temperature", CTLTYPE_INT | CTLFLAG_RD, sc, 0,
+	    temp_sysctl_handler, "IK", "Current die temperature");
+	SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(device_get_sysctl_tree(sc->dev)),
+	    OID_AUTO, "throttle_temperature", CTLTYPE_INT | CTLFLAG_RW, sc,
+	    0, temp_throttle_sysctl_handler, "IK", 
+	    "Throttle CPU when exceeding this temperature");
+}
+
+static int
+imx6_anatop_detach(device_t dev)
+{
+
+	return (EBUSY);
 }
 
 static int
 imx6_anatop_attach(device_t dev)
 {
 	struct imx6_anatop_softc *sc;
-	int err, rid;
+	int err;
 
 	sc = device_get_softc(dev);
+	sc->dev = dev;
 
 	/* Allocate bus_space resources. */
-	rid = 0;
-	sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
-	    RF_ACTIVE);
-	if (sc->mem_res == NULL) {
-		device_printf(dev, "Cannot allocate memory resources\n");
+	if (bus_alloc_resources(dev, imx6_anatop_spec, sc->res)) {
+		device_printf(dev, "Cannot allocate resources\n");
 		err = ENXIO;
 		goto out;
 	}
 
+	err = bus_setup_intr(dev, sc->res[IRQRES], INTR_TYPE_MISC | INTR_MPSAFE,
+	    tempmon_intr, NULL, sc, &sc->temp_intrhand);
+	if (err != 0)
+		goto out;
+
 	imx6_anatop_sc = sc;
+
+	/*
+	 * Other code seen on the net sets this SELFBIASOFF flag around the same
+	 * time the temperature sensor is set up, although it's unclear how the
+	 * two are related (if at all).
+	 */
+	imx6_anatop_write_4(IMX6_ANALOG_PMU_MISC0_SET, 
+	    IMX6_ANALOG_PMU_MISC0_SELFBIASOFF);
+
+	cpufreq_initialize(sc);
+	initialize_tempmon(sc);
+
 	err = 0;
 
 out:
 
-	if (err != 0)
-		imx6_anatop_detach(dev);
+	if (err != 0) {
+		bus_release_resources(dev, imx6_anatop_spec, sc->res);
+	}
 
 	return (err);
 }
@@ -129,7 +482,7 @@ imx6_anatop_probe(device_t dev)
 	if (!ofw_bus_status_okay(dev))
 		return (ENXIO);
 
-        if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0)
+	if (ofw_bus_is_compatible(dev, "fsl,imx6q-anatop") == 0)
 		return (ENXIO);
 
 	device_set_desc(dev, "Freescale i.MX6 Analog PLLs and Power");
@@ -137,6 +490,16 @@ imx6_anatop_probe(device_t dev)
 	return (BUS_PROBE_DEFAULT);
 }
 
+uint32_t 
+imx6_get_cpu_clock()
+{
+	uint32_t div;
+
+	div = imx6_anatop_read_4(IMX6_ANALOG_CCM_PLL_ARM) &
+	    IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK;
+	return (cpufreq_hz_from_div(imx6_anatop_sc, div));
+}
+
 static device_method_t imx6_anatop_methods[] = {
 	/* Device interface */
 	DEVMETHOD(device_probe,  imx6_anatop_probe),

Modified: stable/10/sys/arm/freescale/imx/imx6_anatopreg.h
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatopreg.h	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/freescale/imx/imx6_anatopreg.h	Thu May 15 22:50:06 2014	(r266201)
@@ -33,6 +33,10 @@
 #define	IMX6_ANALOG_CCM_PLL_ARM_SET			0x004
 #define	IMX6_ANALOG_CCM_PLL_ARM_CLR			0x008
 #define	IMX6_ANALOG_CCM_PLL_ARM_TOG			0x00C
+#define	  IMX6_ANALOG_CCM_PLL_ARM_DIV_MASK		  0x7F
+#define	  IMX6_ANALOG_CCM_PLL_ARM_LOCK			  (1U << 31)
+#define	  IMX6_ANALOG_CCM_PLL_ARM_BYPASS		  (1 << 16)
+#define	  IMX6_ANALOG_CCM_PLL_ARM_CLK_SRC_MASK		  (0x03 << 16)
 #define	IMX6_ANALOG_CCM_PLL_USB1			0x010
 #define	IMX6_ANALOG_CCM_PLL_USB1_SET			0x014
 #define	IMX6_ANALOG_CCM_PLL_USB1_CLR			0x018
@@ -81,6 +85,7 @@
 #define	IMX6_ANALOG_CCM_PFD_528_SET			0x104
 #define	IMX6_ANALOG_CCM_PFD_528_CLR			0x108
 #define	IMX6_ANALOG_CCM_PFD_528_TOG			0x10C
+
 #define	IMX6_ANALOG_PMU_REG_CORE			0x140
 #define	  IMX6_ANALOG_PMU_REG2_TARG_SHIFT		  18
 #define	  IMX6_ANALOG_PMU_REG2_TARG_MASK		   \
@@ -92,14 +97,56 @@
 #define	  IMX6_ANALOG_PMU_REG0_TARG_MASK		   \
     (0x1f << IMX6_ANALOG_PMU_REG0_TARG_SHIFT)
 
-#define	IMX6_ANALOG_CCM_MISC0				0x150
-#define	IMX6_ANALOG_CCM_MISC0_SET			0x154
-#define	IMX6_ANALOG_CCM_MISC0_CLR			0x158
-#define	IMX6_ANALOG_CCM_MISC0_TOG			0x15C
-#define	IMX6_ANALOG_CCM_MISC2				0x170
-#define	IMX6_ANALOG_CCM_MISC2_SET			0x174
-#define	IMX6_ANALOG_CCM_MISC2_CLR			0x178
-#define	IMX6_ANALOG_CCM_MISC2_TOG			0x17C
+#define	IMX6_ANALOG_PMU_MISC0				0x150
+#define	IMX6_ANALOG_PMU_MISC0_SET			0x154
+#define	IMX6_ANALOG_PMU_MISC0_CLR			0x158
+#define	IMX6_ANALOG_PMU_MISC0_TOG			0x15C
+#define	  IMX6_ANALOG_PMU_MISC0_SELFBIASOFF		  (1 << 3)
+
+#define	IMX6_ANALOG_PMU_MISC1				0x160
+#define	IMX6_ANALOG_PMU_MISC1_SET			0x164
+#define	IMX6_ANALOG_PMU_MISC1_CLR			0x168
+#define	IMX6_ANALOG_PMU_MISC1_TOG			0x16C
+#define	  IMX6_ANALOG_PMU_MISC1_IRQ_TEMPSENSE		  (1 << 29)
+
+#define	IMX6_ANALOG_PMU_MISC2				0x170
+#define	IMX6_ANALOG_PMU_MISC2_SET			0x174
+#define	IMX6_ANALOG_PMU_MISC2_CLR			0x178
+#define	IMX6_ANALOG_PMU_MISC2_TOG			0x17C
+
+/*
+ * Note that the ANALOG_CCM_MISCn registers are the same as the PMU_MISCn
+ * registers; some bits conceptually belong to the PMU and some to the CCM.
+ */
+#define	IMX6_ANALOG_CCM_MISC0				IMX6_ANALOG_PMU_MISC0
+#define	IMX6_ANALOG_CCM_MISC0_SET			IMX6_ANALOG_PMU_MISC0_SET
+#define	IMX6_ANALOG_CCM_MISC0_CLR			IMX6_ANALOG_PMU_MISC0_CLR
+#define	IMX6_ANALOG_CCM_MISC0_TOG			IMX6_ANALOG_PMU_MISC0_TOG
+
+#define	IMX6_ANALOG_CCM_MISC2				IMX6_ANALOG_PMU_MISC2
+#define	IMX6_ANALOG_CCM_MISC2_SET			IMX6_ANALOG_PMU_MISC2_SET
+#define	IMX6_ANALOG_CCM_MISC2_CLR			IMX6_ANALOG_PMU_MISC2_CLR
+#define	IMX6_ANALOG_CCM_MISC2_TOG			IMX6_ANALOG_PMU_MISC2_TOG
+
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE0			0x180
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE0_SET		0x184
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE0_CLR		0x188
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE0_TOG		0x18C
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE0_TOG		0x18C
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT	 20
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_MASK	  \
+    (0xfff << IMX6_ANALOG_TEMPMON_TEMPSENSE0_ALARM_SHIFT)
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT	  8
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_MASK	  \
+    (0xfff << IMX6_ANALOG_TEMPMON_TEMPSENSE0_TEMP_CNT_SHIFT)
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_VALID		0x4
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_MEASURE	0x2
+#define	  IMX6_ANALOG_TEMPMON_TEMPSENSE0_POWER_DOWN	0x1
+
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE1			0x190
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE1_SET		0x194
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE1_CLR		0x198
+#define	IMX6_ANALOG_TEMPMON_TEMPSENSE1_TOG		0x19C
 
 #define	IMX6_ANALOG_USB1_VBUS_DETECT			0x1A0
 #define	IMX6_ANALOG_USB1_VBUS_DETECT_SET		0x1A4

Modified: stable/10/sys/arm/freescale/imx/imx6_anatopvar.h
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatopvar.h	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/freescale/imx/imx6_anatopvar.h	Thu May 15 22:50:06 2014	(r266201)
@@ -40,4 +40,6 @@
 uint32_t imx6_anatop_read_4(bus_size_t _offset);
 void imx6_anatop_write_4(bus_size_t _offset, uint32_t _value);
 
+uint32_t imx6_get_cpu_clock(void);
+
 #endif

Modified: stable/10/sys/arm/freescale/imx/imx6_machdep.c
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_machdep.c	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/freescale/imx/imx6_machdep.c	Thu May 15 22:50:06 2014	(r266201)
@@ -55,9 +55,6 @@ void
 initarm_early_init(void)
 {
 
-	/* XXX - Get rid of this stuff soon. */
-	boothowto |= RB_VERBOSE|RB_MULTIPLE;
-	bootverbose = 1;
 }
 
 void
@@ -190,3 +187,27 @@ u_int imx_soc_type()
 	return (IMXSOC_6Q);
 }
 
+/*
+ * Early putc routine for EARLY_PRINTF support.  To use, add to kernel config:
+ *   option SOCDEV_PA=0x02000000
+ *   option SOCDEV_VA=0x02000000
+ *   option EARLY_PRINTF
+ * Resist the temptation to change the #if 0 to #ifdef EARLY_PRINTF here. It
+ * makes sense now, but if multiple SOCs do that it will make early_putc another
+ * duplicate symbol to be eliminated on the path to a generic kernel.
+ */
+#if 0 
+static void 
+imx6_early_putc(int c)
+{
+	volatile uint32_t * UART_STAT_REG = (uint32_t *)0x02020098;
+	volatile uint32_t * UART_TX_REG   = (uint32_t *)0x02020040;
+	const uint32_t      UART_TXRDY    = (1 << 3);
+
+	while ((*UART_STAT_REG & UART_TXRDY) == 0)
+		continue;
+	*UART_TX_REG = c;
+}
+early_putc_t *early_putc = imx6_early_putc;
+#endif
+

Modified: stable/10/sys/arm/freescale/vybrid/files.vybrid
==============================================================================
--- stable/10/sys/arm/freescale/vybrid/files.vybrid	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/freescale/vybrid/files.vybrid	Thu May 15 22:50:06 2014	(r266201)
@@ -29,4 +29,5 @@ arm/freescale/vybrid/vf_nfc.c			optional
 arm/freescale/vybrid/vf_ehci.c			optional	ehci
 arm/freescale/vybrid/vf_gpio.c			optional	gpio
 arm/freescale/vybrid/vf_uart.c			optional	uart
+arm/freescale/vybrid/vf_sai.c			optional	sound
 dev/ffec/if_ffec.c				optional	ffec

Copied and modified: stable/10/sys/arm/freescale/vybrid/vf_sai.c (from r261982, head/sys/arm/freescale/vybrid/vf_sai.c)
==============================================================================
--- head/sys/arm/freescale/vybrid/vf_sai.c	Sun Feb 16 16:49:54 2014	(r261982, copy source)
+++ stable/10/sys/arm/freescale/vybrid/vf_sai.c	Thu May 15 22:50:06 2014	(r266201)
@@ -396,7 +396,8 @@ sai_dma_intr(void *arg, int chn)
 	if (sc->pos >= sc->dma_size)
 		sc->pos -= sc->dma_size;
 
-	chn_intr(ch->channel);
+	if (ch->run)
+		chn_intr(ch->channel);
 
 	return (0);
 }
@@ -492,7 +493,7 @@ setup_dma(struct sc_pcminfo *scp)
 	tcd->nbytes = 64;
 
 	tcd->nmajor = 512;
-	tcd->smod = 18;	/* dma_size range */
+	tcd->smod = 17;	/* dma_size range */
 	tcd->dmod = 0;
 	tcd->esg = 0;
 	tcd->soff = 0x4;
@@ -523,6 +524,7 @@ saichan_trigger(kobj_t obj, void *data, 
 #if 0
 		device_printf(scp->dev, "trigger start\n");
 #endif
+		ch->run = 1;
 		break;
 
 	case PCMTRIG_STOP:
@@ -530,6 +532,7 @@ saichan_trigger(kobj_t obj, void *data, 
 #if 0
 		device_printf(scp->dev, "trigger stop or abort\n");
 #endif
+		ch->run = 0;
 		break;
 	}
 
@@ -720,7 +723,7 @@ sai_attach(device_t dev)
 	scp->dev = dev;
 
 	/* DMA */
-	sc->dma_size = 262144;
+	sc->dma_size = 131072;
 
 	/*
 	 * Must use dma_size boundary as modulo feature required.

Modified: stable/10/sys/arm/include/physmem.h
==============================================================================
--- stable/10/sys/arm/include/physmem.h	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/arm/include/physmem.h	Thu May 15 22:50:06 2014	(r266201)
@@ -65,7 +65,7 @@ void arm_physmem_print_tables(void);
 
 #include <machine/ofw_machdep.h>
 
-inline void 
+static inline void 
 arm_physmem_hardware_regions(struct mem_region * mrptr, int mrcount)
 {
 	while (mrcount--) {
@@ -74,7 +74,7 @@ arm_physmem_hardware_regions(struct mem_
 	}
 }
 
-inline void
+static inline void
 arm_physmem_exclude_regions(struct mem_region * mrptr, int mrcount, 
     uint32_t exflags)
 {

Modified: stable/10/sys/boot/fdt/dts/imx6.dtsi
==============================================================================
--- stable/10/sys/boot/fdt/dts/imx6.dtsi	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/boot/fdt/dts/imx6.dtsi	Thu May 15 22:50:06 2014	(r266201)
@@ -97,6 +97,8 @@
 			anatop: anatop@020c8000 {
 				compatible = "fsl,imx6q-anatop";
 				reg = <0x020c8000 0x1000>;
+				interrupt-parent = <&gic>;
+				interrupts = <49>;
 			}
 
 			gpt: timer@02098000 {

Modified: stable/10/sys/boot/fdt/dts/vybrid.dtsi
==============================================================================
--- stable/10/sys/boot/fdt/dts/vybrid.dtsi	Thu May 15 22:35:04 2014	(r266200)
+++ stable/10/sys/boot/fdt/dts/vybrid.dtsi	Thu May 15 22:50:06 2014	(r266201)
@@ -311,6 +311,9 @@
 			interrupt-parent = <&GIC>;
 			status = "disabled";
 			edma-controller = <&edma1>;
+			edma-src-receive = < 8 >;
+			edma-src-transmit = < 9 >;
+			edma-mux-group = < 1 >;
 			clock_names = "sai3", "cko1";
 			iomux_config = < 16 0x2
 					 19 0x2



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405152250.s4FMo6tG051305>