Squashed 'third_party/pico-sdk/' content from commit 2062372d2

Change-Id: Ic20f199d3ed0ea8d3a6a1bbf513f875ec7500cc6
git-subtree-dir: third_party/pico-sdk
git-subtree-split: 2062372d203b372849d573f252cf7c6dc2800c0a
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/src/rp2_common/hardware_timer/CMakeLists.txt b/src/rp2_common/hardware_timer/CMakeLists.txt
new file mode 100644
index 0000000..358f74c
--- /dev/null
+++ b/src/rp2_common/hardware_timer/CMakeLists.txt
@@ -0,0 +1,2 @@
+pico_simple_hardware_target(timer)
+target_link_libraries(hardware_timer INTERFACE hardware_claim)
diff --git a/src/rp2_common/hardware_timer/include/hardware/timer.h b/src/rp2_common/hardware_timer/include/hardware/timer.h
new file mode 100644
index 0000000..1799cd0
--- /dev/null
+++ b/src/rp2_common/hardware_timer/include/hardware/timer.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _HARDWARE_TIMER_H
+#define _HARDWARE_TIMER_H
+
+#include "pico.h"
+#include "hardware/structs/timer.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file hardware/timer.h
+ *  \defgroup hardware_timer hardware_timer
+ *
+ * Low-level hardware timer API
+ *
+ * This API provides medium level access to the timer HW.
+ * See also \ref pico_time which provides higher levels functionality using the hardware timer.
+ *
+ * The timer peripheral on RP2040 supports the following features:
+ *  - single 64-bit counter, incrementing once per microsecond
+ *  - Latching two-stage read of counter, for race-free read over 32 bit bus
+ *  - Four alarms: match on the lower 32 bits of counter, IRQ on match.
+ *
+ * By default the timer uses a one microsecond reference that is generated in the Watchdog (see Section 4.8.2) which is derived
+ * from the clk_ref.
+ *
+ * The timer has 4 alarms, and can output a separate interrupt for each alarm. The alarms match on the lower 32 bits of the 64
+ * bit counter which means they can be fired a maximum of 2^32 microseconds into the future. This is equivalent to:
+ *  - 2^32 ÷ 10^6: ~4295 seconds
+ *  - 4295 ÷ 60: ~72 minutes
+ *
+ * The timer is expected to be used for short sleeps, if you want a longer alarm see the \ref hardware_rtc functions.
+ *
+ * \subsection timer_example Example
+ * \addtogroup hardware_timer
+ *
+ * \include hello_timer.c
+ *
+ * \see pico_time
+ */
+
+// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_TIMER, Enable/disable assertions in the timer module, type=bool, default=0, group=hardware_timer
+#ifndef PARAM_ASSERTIONS_ENABLED_TIMER
+#define PARAM_ASSERTIONS_ENABLED_TIMER 0
+#endif
+
+static inline void check_hardware_alarm_num_param(__unused uint alarm_num) {
+    invalid_params_if(TIMER, alarm_num >= NUM_TIMERS);
+}
+
+/*! \brief Return a 32 bit timestamp value in microseconds
+*  \ingroup hardware_timer
+*
+* Returns the low 32 bits of the hardware timer.
+* \note This value wraps roughly every 1 hour 11 minutes and 35 seconds.
+*
+* \return the 32 bit timestamp
+*/
+static inline uint32_t time_us_32(void) {
+    return timer_hw->timerawl;
+}
+
+/*! \brief Return the current 64 bit timestamp value in microseconds
+*  \ingroup hardware_timer
+*
+* Returns the full 64 bits of the hardware timer. The \ref pico_time and other functions rely on the fact that this
+* value monotonically increases from power up. As such it is expected that this value counts upwards and never wraps
+* (we apologize for introducing a potential year 5851444 bug).
+*
+* \return the 64 bit timestamp
+*/
+uint64_t time_us_64(void);
+
+/*! \brief Busy wait wasting cycles for the given (32 bit) number of microseconds
+ *  \ingroup hardware_timer
+ *
+ * \param delay_us delay amount in microseconds
+ */
+void busy_wait_us_32(uint32_t delay_us);
+
+/*! \brief Busy wait wasting cycles for the given (64 bit) number of microseconds
+ *  \ingroup hardware_timer
+ *
+ * \param delay_us delay amount in microseconds
+ */
+void busy_wait_us(uint64_t delay_us);
+
+/*! \brief Busy wait wasting cycles for the given number of milliseconds
+ *  \ingroup hardware_timer
+ *
+ * \param delay_ms delay amount in milliseconds
+ */
+void busy_wait_ms(uint32_t delay_ms);
+
+/*! \brief Busy wait wasting cycles until after the specified timestamp
+ *  \ingroup hardware_timer
+ *
+ * \param t Absolute time to wait until
+ */
+void busy_wait_until(absolute_time_t t);
+
+/*! \brief Check if the specified timestamp has been reached
+ *  \ingroup hardware_timer
+ *
+ * \param t Absolute time to compare against current time
+ * \return true if it is now after the specified timestamp
+ */
+static inline bool time_reached(absolute_time_t t) {
+    uint64_t target = to_us_since_boot(t);
+    uint32_t hi_target = (uint32_t)(target >> 32u);
+    uint32_t hi = timer_hw->timerawh;
+    return (hi >= hi_target && (timer_hw->timerawl >= (uint32_t) target || hi != hi_target));
+}
+
+/*! Callback function type for hardware alarms
+ *  \ingroup hardware_timer
+ *
+ * \param alarm_num the hardware alarm number
+ * \sa hardware_alarm_set_callback()
+ */
+typedef void (*hardware_alarm_callback_t)(uint alarm_num);
+
+/*! \brief cooperatively claim the use of this hardware alarm_num
+ *  \ingroup hardware_timer
+ *
+ * This method hard asserts if the hardware alarm is currently claimed.
+ *
+ * \param alarm_num the hardware alarm to claim
+ * \sa hardware_claiming
+ */
+void hardware_alarm_claim(uint alarm_num);
+
+/*! \brief cooperatively release the claim on use of this hardware alarm_num
+ *  \ingroup hardware_timer
+ *
+ * \param alarm_num the hardware alarm to unclaim
+ * \sa hardware_claiming
+ */
+void hardware_alarm_unclaim(uint alarm_num);
+
+/*! \brief Determine if a hardware alarm has been claimed
+ *  \ingroup hardware_timer
+ *
+ * \param alarm_num the hardware alarm number
+ * \return true if claimed, false otherwise
+ * \see hardware_alarm_claim
+ */
+bool hardware_alarm_is_claimed(uint alarm_num);
+
+/*! \brief Enable/Disable a callback for a hardware timer on this core
+ *  \ingroup hardware_timer
+ *
+ * This method enables/disables the alarm IRQ for the specified hardware alarm on the
+ * calling core, and set the specified callback to be associated with that alarm.
+ *
+ * This callback will be used for the timeout set via hardware_alarm_set_target
+ *
+ * \note This will install the handler on the current core if the IRQ handler isn't already set.
+ * Therefore the user has the opportunity to call this up from the core of their choice
+ *
+ * \param alarm_num the hardware alarm number
+ * \param callback the callback to install, or NULL to unset
+ *
+ * \sa hardware_alarm_set_target()
+ */
+void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback);
+
+/**
+ * \brief Set the current target for the specified hardware alarm
+ * \ingroup hardware_timer
+ *
+ * This will replace any existing target
+ *
+ * @param alarm_num the hardware alarm number
+ * @param t the target timestamp
+ * @return true if the target was "missed"; i.e. it was in the past, or occurred before a future hardware timeout could be set
+ */
+bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t);
+
+/**
+ * \brief Cancel an existing target (if any) for a given hardware_alarm
+ * \ingroup hardware_timer
+ *
+ * @param alarm_num
+ */
+
+void hardware_alarm_cancel(uint alarm_num);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/rp2_common/hardware_timer/timer.c b/src/rp2_common/hardware_timer/timer.c
new file mode 100644
index 0000000..f13d249
--- /dev/null
+++ b/src/rp2_common/hardware_timer/timer.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "hardware/timer.h"
+#include "hardware/irq.h"
+#include "hardware/sync.h"
+#include "hardware/claim.h"
+
+check_hw_layout(timer_hw_t, ints, TIMER_INTS_OFFSET);
+
+static hardware_alarm_callback_t alarm_callbacks[NUM_TIMERS];
+static uint32_t target_hi[NUM_TIMERS];
+static uint8_t timer_callbacks_pending;
+
+static_assert(NUM_TIMERS <= 4, "");
+static uint8_t claimed;
+
+void hardware_alarm_claim(uint alarm_num) {
+    check_hardware_alarm_num_param(alarm_num);
+    hw_claim_or_assert(&claimed, alarm_num, "Hardware alarm %d already claimed");
+}
+
+void hardware_alarm_unclaim(uint alarm_num) {
+    check_hardware_alarm_num_param(alarm_num);
+    hw_claim_clear(&claimed, alarm_num);
+}
+
+bool hardware_alarm_is_claimed(uint alarm_num) {
+    check_hardware_alarm_num_param(alarm_num);
+    return hw_is_claimed(&claimed, alarm_num);
+}
+
+/// tag::time_us_64[]
+uint64_t time_us_64() {
+    // Need to make sure that the upper 32 bits of the timer
+    // don't change, so read that first
+    uint32_t hi = timer_hw->timerawh;
+    uint32_t lo;
+    do {
+        // Read the lower 32 bits
+        lo = timer_hw->timerawl;
+        // Now read the upper 32 bits again and
+        // check that it hasn't incremented. If it has loop around
+        // and read the lower 32 bits again to get an accurate value
+        uint32_t next_hi = timer_hw->timerawh;
+        if (hi == next_hi) break;
+        hi = next_hi;
+    } while (true);
+    return ((uint64_t) hi << 32u) | lo;
+}
+/// end::time_us_64[]
+
+/// \tag::busy_wait[]
+void busy_wait_us_32(uint32_t delay_us) {
+    if (0 <= (int32_t)delay_us) {
+        // we only allow 31 bits, otherwise we could have a race in the loop below with
+        // values very close to 2^32
+        uint32_t start = timer_hw->timerawl;
+        while (timer_hw->timerawl - start < delay_us) {
+            tight_loop_contents();
+        }
+    } else {
+        busy_wait_us(delay_us);
+    }
+}
+
+void busy_wait_us(uint64_t delay_us) {
+    uint64_t base = time_us_64();
+    uint64_t target = base + delay_us;
+    if (target < base) {
+        target = (uint64_t)-1;
+    }
+    absolute_time_t t;
+    update_us_since_boot(&t, target);
+    busy_wait_until(t);
+}
+
+void busy_wait_ms(uint32_t delay_ms)
+{
+    if (delay_ms <= 0x7fffffffu / 1000) {
+        busy_wait_us_32(delay_ms * 1000);
+    } else {
+        busy_wait_us(delay_ms * 1000ull);
+    }
+}
+
+void busy_wait_until(absolute_time_t t) {
+    uint64_t target = to_us_since_boot(t);
+    uint32_t hi_target = (uint32_t)(target >> 32u);
+    uint32_t hi = timer_hw->timerawh;
+    while (hi < hi_target) {
+        hi = timer_hw->timerawh;
+        tight_loop_contents();
+    }
+    while (hi == hi_target && timer_hw->timerawl < (uint32_t) target) {
+        hi = timer_hw->timerawh;
+        tight_loop_contents();
+    }
+}
+/// \end::busy_wait[]
+
+static inline uint harware_alarm_irq_number(uint alarm_num) {
+    return TIMER_IRQ_0 + alarm_num;
+}
+
+static void hardware_alarm_irq_handler(void) {
+    // Determine which timer this IRQ is for
+    uint32_t ipsr;
+    __asm volatile ("mrs %0, ipsr" : "=r" (ipsr)::);
+    uint alarm_num = (ipsr & 0x3fu) - 16 - TIMER_IRQ_0;
+    check_hardware_alarm_num_param(alarm_num);
+
+    hardware_alarm_callback_t callback = NULL;
+
+    spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+    uint32_t save = spin_lock_blocking(lock);
+    // Clear the timer IRQ (inside lock, because we check whether we have handled the IRQ yet in alarm_set by looking at the interrupt status
+    timer_hw->intr = 1u << alarm_num;
+
+    // make sure the IRQ is still valid
+    if (timer_callbacks_pending & (1u << alarm_num)) {
+        // Now check whether we have a timer event to handle that isn't already obsolete (this could happen if we
+        // were already in the IRQ handler before someone else changed the timer setup
+        if (timer_hw->timerawh >= target_hi[alarm_num]) {
+            // we have reached the right high word as well as low word value
+            callback = alarm_callbacks[alarm_num];
+            timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
+        } else {
+            // try again in 2^32 us
+            timer_hw->alarm[alarm_num] = timer_hw->alarm[alarm_num]; // re-arm the timer
+        }
+    }
+
+    spin_unlock(lock, save);
+
+    if (callback) {
+        callback(alarm_num);
+    }
+}
+
+void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback) {
+    // todo check current core owner
+    //  note this should probably be subsumed by irq_set_exclusive_handler anyway, since that
+    //  should disallow IRQ handlers on both cores
+    check_hardware_alarm_num_param(alarm_num);
+    uint irq_num = harware_alarm_irq_number(alarm_num);
+    spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+    uint32_t save = spin_lock_blocking(lock);
+    if (callback) {
+        if (hardware_alarm_irq_handler != irq_get_vtable_handler(irq_num)) {
+            // note that set_exclusive will silently allow you to set the handler to the same thing
+            // since it is idempotent, which means we don't need to worry about locking ourselves
+            irq_set_exclusive_handler(irq_num, hardware_alarm_irq_handler);
+            irq_set_enabled(irq_num, true);
+            // Enable interrupt in block and at processor
+            hw_set_bits(&timer_hw->inte, 1u << alarm_num);
+        }
+        alarm_callbacks[alarm_num] = callback;
+    } else {
+        alarm_callbacks[alarm_num] = NULL;
+        timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
+        irq_remove_handler(irq_num, hardware_alarm_irq_handler);
+        irq_set_enabled(irq_num, false);
+    }
+    spin_unlock(lock, save);
+}
+
+bool hardware_alarm_set_target(uint alarm_num, absolute_time_t target) {
+    bool missed;
+    uint64_t now = time_us_64();
+    uint64_t t = to_us_since_boot(target);
+    if (now >= t) {
+        missed = true;
+    } else {
+        missed = false;
+
+        // 1) actually set the hardware timer
+        spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+        uint32_t save = spin_lock_blocking(lock);
+        uint8_t old_timer_callbacks_pending = timer_callbacks_pending;
+        timer_callbacks_pending |= (uint8_t)(1u << alarm_num);
+        timer_hw->intr = 1u << alarm_num; // clear any IRQ
+        timer_hw->alarm[alarm_num] = (uint32_t) t;
+        // Set the alarm. Writing time should arm it
+        target_hi[alarm_num] = (uint32_t)(t >> 32u);
+
+        // 2) check for races
+        if (!(timer_hw->armed & 1u << alarm_num)) {
+            // not armed, so has already fired .. IRQ must be pending (we are still under lock)
+            assert(timer_hw->ints & 1u << alarm_num);
+        } else {
+            if (time_us_64() >= t) {
+                // we are already at or past the right time; there is no point in us racing against the IRQ
+                // we are about to generate. note however that, if there was already a timer pending before,
+                // then we still let the IRQ fire, as whatever it was, is not handled by our setting missed=true here
+                missed = true;
+                if (timer_callbacks_pending != old_timer_callbacks_pending) {
+                    // disarm the timer
+                    timer_hw->armed = 1u << alarm_num;
+                    // clear the IRQ...
+                    timer_hw->intr = 1u << alarm_num;
+                    // ... including anything pending on the processor - perhaps unnecessary, but
+                    // our timer flag says we aren't expecting anything.
+                    irq_clear(harware_alarm_irq_number(alarm_num));
+                    // and clear our flag so that if the IRQ handler is already active (because it is on
+                    // the other core) it will also skip doing anything
+                    timer_callbacks_pending = old_timer_callbacks_pending;
+                }
+            }
+        }
+        spin_unlock(lock, save);
+        // note at this point any pending timer IRQ can likely run
+    }
+    return missed;
+}
+
+void hardware_alarm_cancel(uint alarm_num) {
+    check_hardware_alarm_num_param(alarm_num);
+
+    spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
+    uint32_t save = spin_lock_blocking(lock);
+    timer_hw->armed = 1u << alarm_num;
+    timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
+    spin_unlock(lock, save);
+}
+
+