zephyr/drivers/serial/uart_pl011_ambiq.h
Hao Luo 3c1fd19d96 drivers: serial: pl011: Add support for Ambiq Apollo3 SoCs UART
Apollo3 SoCs have different UART register design compared with
that of Apollo4 SoCs, we need to change the offset and mask for
the power status check

Signed-off-by: Hao Luo <hluo@ambiq.com>
2024-05-07 18:57:19 +02:00

96 lines
4 KiB
C

/*
* Copyright (c) 2023 Antmicro <www.antmicro.com>
*
* 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 "uart_pl011_registers.h"
#define PWRCTRL_MAX_WAIT_US 5
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;
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);
}
/* Problem: writes to power configure register takes some time to take effective.
* Solution: Check device's power status to ensure that register has taken effective.
* Note: busy wait is not allowed to use here due to UART is initiated before timer starts.
*/
#if defined(CONFIG_SOC_SERIES_APOLLO3X)
#define DEVPWRSTATUS_OFFSET 0x10
#define HCPA_MASK 0x4
#define AMBIQ_UART_DEFINE(n) \
static int pwr_on_ambiq_uart_##n(void) \
{ \
uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \
DT_INST_PHA(n, ambiq_pwrcfg, offset); \
uint32_t pwr_status_addr = addr + DEVPWRSTATUS_OFFSET; \
sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \
while (!(sys_read32(pwr_status_addr) & HCPA_MASK)) { \
}; \
return 0; \
} \
static inline int clk_enable_ambiq_uart_##n(const struct device *dev, uint32_t clk) \
{ \
return clk_enable_ambiq_uart(dev, clk); \
}
#else
#define DEVPWRSTATUS_OFFSET 0x4
#define AMBIQ_UART_DEFINE(n) \
static int pwr_on_ambiq_uart_##n(void) \
{ \
uint32_t addr = DT_REG_ADDR(DT_INST_PHANDLE(n, ambiq_pwrcfg)) + \
DT_INST_PHA(n, ambiq_pwrcfg, offset); \
uint32_t pwr_status_addr = addr + DEVPWRSTATUS_OFFSET; \
sys_write32((sys_read32(addr) | DT_INST_PHA(n, ambiq_pwrcfg, mask)), addr); \
while ((sys_read32(pwr_status_addr) & DT_INST_PHA(n, ambiq_pwrcfg, mask)) != \
DT_INST_PHA(n, ambiq_pwrcfg, mask)) { \
}; \
return 0; \
} \
static inline int clk_enable_ambiq_uart_##n(const struct device *dev, uint32_t clk) \
{ \
return clk_enable_ambiq_uart(dev, clk); \
}
#endif
#endif /* ZEPHYR_DRIVERS_SERIAL_UART_PL011_AMBIQ_H_ */