mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-23 22:14:54 +00:00

Add basic Power Management Unit (PMU) driver for Exynos SoCs. For now it's only capable of changing UART path in PMU, which is needed for E850-96 board. The driver's structure resembles the exynos-pmu driver from Linux kernel, and although it's very basic and slim at the moment, it can be easily extended in future if the need arises. UCLASS_NOP is used, as there are no benefits in using more elaborate classes like UCLASS_MISC in this case. The DM_FLAG_PROBE_AFTER_BIND flag is added in bind function, as the probe function must be always called for this driver. Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org> Reviewed-by: Chanho Park <chanho61.park@samsung.com> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
102 lines
2.4 KiB
C
102 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2023 Linaro Ltd.
|
|
* Author: Sam Protsenko <semen.protsenko@linaro.org>
|
|
*
|
|
* Exynos PMU (Power Management Unit) driver.
|
|
*/
|
|
|
|
#include <dm.h>
|
|
#include <errno.h>
|
|
#include <regmap.h>
|
|
#include <syscon.h>
|
|
#include <linux/bitops.h>
|
|
#include <linux/err.h>
|
|
|
|
#define EXYNOS850_UART_IO_SHARE_CTRL 0x0760
|
|
#define SEL_RXD_AP_UART_SHIFT 16
|
|
#define SEL_RXD_AP_UART_MASK GENMASK(17, 16)
|
|
#define SEL_TXD_GPIO_1_SHIFT 20
|
|
#define SEL_TXD_GPIO_1_MASK GENMASK(21, 20)
|
|
#define RXD_GPIO_1 0x3
|
|
#define TXD_AP_UART 0x0
|
|
|
|
struct exynos_pmu {
|
|
struct udevice *dev;
|
|
const struct exynos_pmu_data *pmu_data;
|
|
struct regmap *regmap;
|
|
};
|
|
|
|
struct exynos_pmu_data {
|
|
int (*pmu_init)(struct exynos_pmu *priv);
|
|
};
|
|
|
|
static int exynos850_pmu_init(struct exynos_pmu *priv)
|
|
{
|
|
ofnode node;
|
|
bool uart_debug_1;
|
|
unsigned int offset, mask, value;
|
|
|
|
node = dev_ofnode(priv->dev);
|
|
uart_debug_1 = ofnode_read_bool(node, "samsung,uart-debug-1");
|
|
if (!uart_debug_1)
|
|
return 0;
|
|
|
|
/*
|
|
* If uart1_pins are used for serial, AP UART lines have to be muxed
|
|
* in PMU block to UART_DEBUG_1 path (GPIO_1). By default (reset value)
|
|
* UART_DEBUG_0 path (uart0_pins) is connected to AP UART lines.
|
|
*/
|
|
offset = EXYNOS850_UART_IO_SHARE_CTRL;
|
|
mask = SEL_RXD_AP_UART_MASK | SEL_TXD_GPIO_1_MASK;
|
|
value = RXD_GPIO_1 << SEL_RXD_AP_UART_SHIFT |
|
|
TXD_AP_UART << SEL_TXD_GPIO_1_SHIFT;
|
|
return regmap_update_bits(priv->regmap, offset, mask, value);
|
|
}
|
|
|
|
static const struct exynos_pmu_data exynos850_pmu_data = {
|
|
.pmu_init = exynos850_pmu_init,
|
|
};
|
|
|
|
static int exynos_pmu_bind(struct udevice *dev)
|
|
{
|
|
dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
|
|
return 0;
|
|
}
|
|
|
|
static int exynos_pmu_probe(struct udevice *dev)
|
|
{
|
|
ofnode node;
|
|
struct exynos_pmu *priv;
|
|
|
|
priv = dev_get_priv(dev);
|
|
priv->dev = dev;
|
|
|
|
node = dev_ofnode(dev);
|
|
priv->regmap = syscon_node_to_regmap(node);
|
|
if (IS_ERR(priv->regmap))
|
|
return PTR_ERR(priv->regmap);
|
|
|
|
priv->pmu_data = (struct exynos_pmu_data *)dev_get_driver_data(dev);
|
|
if (priv->pmu_data && priv->pmu_data->pmu_init)
|
|
return priv->pmu_data->pmu_init(priv);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct udevice_id exynos_pmu_ids[] = {
|
|
{
|
|
.compatible = "samsung,exynos850-pmu",
|
|
.data = (ulong)&exynos850_pmu_data
|
|
},
|
|
{ /* sentinel */ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(exynos_pmu) = {
|
|
.name = "exynos-pmu",
|
|
.id = UCLASS_NOP,
|
|
.of_match = exynos_pmu_ids,
|
|
.bind = exynos_pmu_bind,
|
|
.probe = exynos_pmu_probe,
|
|
.priv_auto = sizeof(struct exynos_pmu),
|
|
};
|