blob: ca3f5ca7dd527e246308a2bff6fb70fea3dea4ad [file] [log] [blame]
Tien Fong Chee3a07a2c2024-09-18 16:43:02 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2025 Altera Corporation <www.altera.com>
4 */
5
6/*
7 * This driver supports the SOCFPGA System Manager Register block which
8 * aggregates different peripheral function into one area.
9 * On 64 bit ARM parts, the system manager only can be accessed during
10 * EL3 mode. At lower exception level a SMC call is required to perform
11 * the read and write operation.
12 */
13
14#define LOG_CATEGORY UCLASS_NOP
15
16#include <dm.h>
17#include <log.h>
18#include <misc.h>
19#include <asm/io.h>
20#include <asm/system.h>
21#include <asm/arch/altera-sysmgr.h>
22#include <asm/arch/smc_api.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/intel-smc.h>
26
27static int altr_sysmgr_read_generic(struct udevice *dev, u32 *addr, u32 *value)
28{
29 u64 args[1];
30 u64 ret_arg;
31 int ret = 0;
32
33 debug("%s: %s(dev=%p, addr=0x%lx):\n", __func__,
34 dev->name, dev, (uintptr_t)addr);
35
36 if (current_el() == 3) {
37 ret_arg = readl((uintptr_t)addr);
38 } else {
39 if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) {
40 args[0] = (u64)(uintptr_t)addr;
41 ret = invoke_smc(INTEL_SIP_SMC_REG_READ, args, 1, &ret_arg, 1);
42 } else {
43 pr_err("%s Failed to read system manager at lower privilege and without BL31\n",
44 dev->name);
45 return -EPROTONOSUPPORT;
46 }
47 }
48
49 *value = (u32)ret_arg;
50 return ret;
51}
52
53static int altr_sysmgr_write_generic(struct udevice *dev, u32 *addr, u32 value)
54{
55 u64 args[2];
56 int ret = 0;
57
58 debug("%s: %s(dev=%p, addr=0x%lx, val=0x%x):\n", __func__,
59 dev->name, dev, (uintptr_t)addr, value);
60
61 if (current_el() == 3) {
62 writel(value, (uintptr_t)addr);
63 } else {
64 if (!(IS_ENABLED(CONFIG_SPL_BUILD)) && IS_ENABLED(CONFIG_SPL_ATF)) {
65 args[0] = (u64)(uintptr_t)(addr);
66 args[1] = value;
67 ret = invoke_smc(INTEL_SIP_SMC_REG_WRITE, args, 2, NULL, 0);
68 } else {
69 pr_err("%s Failed to write to system manager at lower privilege and without BL31\n",
70 dev->name);
71 return -EPROTONOSUPPORT;
72 }
73 }
74
75 return ret;
76}
77
78static int altr_sysmgr_probe(struct udevice *dev)
79{
80 fdt_addr_t addr;
81 struct altr_sysmgr_priv *altr_priv = dev_get_priv(dev);
82
83 debug("%s: %s(dev=%p):\n", __func__, dev->name, dev);
84 addr = dev_read_addr(dev);
85 if (addr == FDT_ADDR_T_NONE) {
86 pr_err("%s dev_read_addr() failed\n", dev->name);
87 return -ENODEV;
88 }
89
90 altr_priv->regs = (void __iomem *)addr;
91 return 0;
92}
93
94static const struct altr_sysmgr_ops sysmgr_ops = {
95 .read = altr_sysmgr_read_generic,
96 .write = altr_sysmgr_write_generic,
97};
98
99static const struct udevice_id altr_sysmgr_ids[] = {
100 { .compatible = "altr,sys-mgr-s10" },
101 { .compatible = "altr,sys-mgr" },
102 { },
103};
104
105U_BOOT_DRIVER(altr_sysmgr) = {
106 .name = "altr_sysmgr",
107 .id = UCLASS_NOP,
108 .of_match = altr_sysmgr_ids,
109 .probe = altr_sysmgr_probe,
110 .ops = &sysmgr_ops,
111 .priv_auto = sizeof(struct altr_sysmgr_priv),
112 .flags = DM_FLAG_PRE_RELOC,
113};