The conditions needed to declare `uart_ambiq_pm_action()` in `uart_pl011_ambiq.h` and the conditions needed to use it in `uart_pl011.c` differed, which would result in a warning promoted to error during weekly CI runs. Ensure that the conditions match to remove the warning / error. ```cpp if defined(CONFIG_SOC_SERIES_APOLLO3X) || \ defined(CONFIG_SOC_SERIES_APOLLO5X) ``` Signed-off-by: Chris Friedt <cfriedt@tenstorrent.com>
209 lines
5.5 KiB
C
209 lines
5.5 KiB
C
/*
|
|
* Copyright (c) 2023 Antmicro <www.antmicro.com>
|
|
* Copyright (c) 2025 Linumiz GmbH
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#ifndef ZEPHYR_DRIVERS_SERIAL_UART_PL011_AMBIQ_H_
|
|
#define ZEPHYR_DRIVERS_SERIAL_UART_PL011_AMBIQ_H_
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/pm/device.h>
|
|
#include <zephyr/pm/policy.h>
|
|
|
|
#include "uart_pl011_registers.h"
|
|
#include <soc.h>
|
|
|
|
static inline void pl011_ambiq_enable_clk(const struct device *dev)
|
|
{
|
|
get_uart(dev)->cr |= PL011_CR_AMBIQ_CLKEN;
|
|
}
|
|
|
|
static inline int pl011_ambiq_clk_set(const struct device *dev, uint32_t clk)
|
|
{
|
|
uint8_t clksel;
|
|
|
|
switch (clk) {
|
|
case 3000000:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_3MHZ;
|
|
break;
|
|
case 6000000:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_6MHZ;
|
|
break;
|
|
case 12000000:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_12MHZ;
|
|
break;
|
|
case 24000000:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_24MHZ;
|
|
break;
|
|
#if !defined(CONFIG_SOC_SERIES_APOLLO2X) && !defined(CONFIG_SOC_SERIES_APOLLO3X)
|
|
case 48000000:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_48MHZ;
|
|
break;
|
|
#if !defined(CONFIG_SOC_SERIES_APOLLO4X)
|
|
case AM_HAL_UART_PLLCLK_FREQ:
|
|
clksel = PL011_CR_AMBIQ_CLKSEL_PLL;
|
|
break;
|
|
#endif
|
|
#endif
|
|
default:
|
|
return -EINVAL;
|
|
}
|
|
|
|
get_uart(dev)->cr |= FIELD_PREP(PL011_CR_AMBIQ_CLKSEL, clksel);
|
|
return 0;
|
|
}
|
|
|
|
static inline int clk_enable_ambiq_uart(const struct device *dev, uint32_t clk)
|
|
{
|
|
pl011_ambiq_enable_clk(dev);
|
|
return pl011_ambiq_clk_set(dev, clk);
|
|
}
|
|
|
|
#if defined(CONFIG_SOC_SERIES_APOLLO3X) || defined(CONFIG_SOC_SERIES_APOLLO5X)
|
|
#ifdef CONFIG_PM_DEVICE
|
|
|
|
/* Register status record.
|
|
* The register status will be preserved to this variable before entering sleep mode,
|
|
* and they will be restored after wake up.
|
|
*/
|
|
typedef struct {
|
|
bool bValid;
|
|
uint32_t regILPR;
|
|
uint32_t regIBRD;
|
|
uint32_t regFBRD;
|
|
uint32_t regLCRH;
|
|
uint32_t regCR;
|
|
uint32_t regIFLS;
|
|
uint32_t regIER;
|
|
} uart_register_state_t;
|
|
static uart_register_state_t sRegState[AM_REG_UART_NUM_MODULES];
|
|
|
|
static int uart_ambiq_pm_action(const struct device *dev, enum pm_device_action action)
|
|
{
|
|
int key;
|
|
|
|
/*Uart module number*/
|
|
uint32_t ui32Module = ((uint32_t)get_uart(dev) == UART0_BASE) ? 0 : 1;
|
|
|
|
/*Uart Power module*/
|
|
am_hal_pwrctrl_periph_e eUARTPowerModule =
|
|
((am_hal_pwrctrl_periph_e)(AM_HAL_PWRCTRL_PERIPH_UART0 + ui32Module));
|
|
|
|
/*Uart register status*/
|
|
uart_register_state_t *pRegisterStatus = &sRegState[ui32Module];
|
|
|
|
/* Decode the requested power state and update UART operation accordingly.*/
|
|
switch (action) {
|
|
|
|
/* Turn on the UART. */
|
|
case PM_DEVICE_ACTION_RESUME:
|
|
|
|
/* Make sure we don't try to restore an invalid state.*/
|
|
if (!pRegisterStatus->bValid) {
|
|
return -EPERM;
|
|
}
|
|
|
|
/*The resume and suspend actions may be executed back-to-back,
|
|
* so we add a busy wait here for stabilization.
|
|
*/
|
|
k_busy_wait(100);
|
|
|
|
/* Enable power control.*/
|
|
am_hal_pwrctrl_periph_enable(eUARTPowerModule);
|
|
|
|
/* Restore UART registers*/
|
|
key = irq_lock();
|
|
|
|
UARTn(ui32Module)->ILPR = pRegisterStatus->regILPR;
|
|
UARTn(ui32Module)->IBRD = pRegisterStatus->regIBRD;
|
|
UARTn(ui32Module)->FBRD = pRegisterStatus->regFBRD;
|
|
UARTn(ui32Module)->LCRH = pRegisterStatus->regLCRH;
|
|
UARTn(ui32Module)->CR = pRegisterStatus->regCR;
|
|
UARTn(ui32Module)->IFLS = pRegisterStatus->regIFLS;
|
|
UARTn(ui32Module)->IER = pRegisterStatus->regIER;
|
|
pRegisterStatus->bValid = false;
|
|
|
|
irq_unlock(key);
|
|
|
|
return 0;
|
|
case PM_DEVICE_ACTION_SUSPEND:
|
|
|
|
while ((get_uart(dev)->fr & PL011_FR_BUSY) != 0) {
|
|
}
|
|
|
|
/* Preserve UART registers*/
|
|
key = irq_lock();
|
|
|
|
pRegisterStatus->regILPR = UARTn(ui32Module)->ILPR;
|
|
pRegisterStatus->regIBRD = UARTn(ui32Module)->IBRD;
|
|
pRegisterStatus->regFBRD = UARTn(ui32Module)->FBRD;
|
|
pRegisterStatus->regLCRH = UARTn(ui32Module)->LCRH;
|
|
pRegisterStatus->regCR = UARTn(ui32Module)->CR;
|
|
pRegisterStatus->regIFLS = UARTn(ui32Module)->IFLS;
|
|
pRegisterStatus->regIER = UARTn(ui32Module)->IER;
|
|
pRegisterStatus->bValid = true;
|
|
|
|
irq_unlock(key);
|
|
|
|
/* Clear all interrupts before sleeping as having a pending UART
|
|
* interrupt burns power.
|
|
*/
|
|
UARTn(ui32Module)->IEC = 0xFFFFFFFF;
|
|
|
|
/* If the user is going to sleep, certain bits of the CR register
|
|
* need to be 0 to be low power and have the UART shut off.
|
|
* Since the user either wishes to retain state which takes place
|
|
* above or the user does not wish to retain state, it is acceptable
|
|
* to set the entire CR register to 0.
|
|
*/
|
|
UARTn(ui32Module)->CR = 0;
|
|
|
|
/* Disable power control.*/
|
|
am_hal_pwrctrl_periph_disable(eUARTPowerModule);
|
|
return 0;
|
|
default:
|
|
return -ENOTSUP;
|
|
}
|
|
}
|
|
#endif /* CONFIG_PM_DEVICE */
|
|
#endif /* !defined(CONFIG_SOC_SERIES_APOLLO2X) */
|
|
|
|
|
|
static inline uint32_t uart_get_module_index(const struct device *dev)
|
|
{
|
|
uintptr_t base = ((const struct pl011_config *)dev->config)->_mmio.addr;
|
|
|
|
return (uint32_t)((base - UART0_BASE) / (UART1_BASE - UART0_BASE));
|
|
}
|
|
|
|
static int pwr_on_ambiq_pl011_uart(const struct device *dev)
|
|
{
|
|
uint32_t module = uart_get_module_index(dev);
|
|
|
|
#if defined(CONFIG_SOC_SERIES_APOLLO2X)
|
|
uint32_t eUARTPowerModule = (AM_HAL_PWRCTRL_UART0 << module);
|
|
|
|
am_hal_pwrctrl_periph_enable(eUARTPowerModule);
|
|
return 0;
|
|
#else
|
|
am_hal_pwrctrl_periph_e eUARTPowerModule = AM_HAL_PWRCTRL_PERIPH_UART0 + module;
|
|
|
|
return am_hal_pwrctrl_periph_enable(eUARTPowerModule);
|
|
#endif
|
|
}
|
|
|
|
static inline int clk_enable_ambiq_pl011_uart(const struct device *dev, uint32_t clk)
|
|
{
|
|
#if defined(CONFIG_SOC_SERIES_APOLLO2X)
|
|
uint32_t module = uart_get_module_index(dev);
|
|
|
|
am_hal_clkgen_uarten_set(module, AM_HAL_CLKGEN_UARTEN_EN);
|
|
#endif
|
|
return clk_enable_ambiq_uart(dev, clk);
|
|
}
|
|
|
|
#endif /* ZEPHYR_DRIVERS_SERIAL_UART_PL011_AMBIQ_H_ */
|