96 lines
4.0 KiB
C
96 lines
4.0 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_ */
|