blob: 914fd11c9894a5dace2bbceaf1489db61abf90ed [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Beniamino Galvanic7757d42016-05-08 08:30:17 +02002/*
3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com>
4 *
Beniamino Galvanic7757d42016-05-08 08:30:17 +02005 * Secure monitor calls.
6 */
7
8#include <common.h>
Alexey Romanov67c03a92023-09-21 11:13:40 +03009#include <dm.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060010#include <log.h>
Alexey Romanov67c03a92023-09-21 11:13:40 +030011#include <regmap.h>
Alexey Romanov7cd53e02023-09-21 11:13:41 +030012#include <sm.h>
Alexey Romanov67c03a92023-09-21 11:13:40 +030013#include <syscon.h>
Neil Armstrong0ef8e402019-06-12 11:49:06 +020014#include <asm/arch/sm.h>
Simon Glass90526e92020-05-10 11:39:56 -060015#include <asm/cache.h>
Simon Glass401d1c42020-10-30 21:38:53 -060016#include <asm/global_data.h>
Simon Glass25a58182020-05-10 11:40:06 -060017#include <asm/ptrace.h>
Simon Glasscd93d622020-05-10 11:40:13 -060018#include <linux/bitops.h>
Simon Glass61b29b82020-02-03 07:36:15 -070019#include <linux/err.h>
Beniamino Galvanic7757d42016-05-08 08:30:17 +020020#include <linux/kernel.h>
Neil Armstrongb1dd7de2019-08-06 17:28:36 +020021#include <linux/bitfield.h>
Alexey Romanov7cd53e02023-09-21 11:13:41 +030022#include <meson/sm.h>
Beniamino Galvanic7757d42016-05-08 08:30:17 +020023
Alexey Romanov7cd53e02023-09-21 11:13:41 +030024static inline struct udevice *meson_get_sm_device(void)
Beniamino Galvanic7757d42016-05-08 08:30:17 +020025{
Alexey Romanov7cd53e02023-09-21 11:13:41 +030026 struct udevice *dev;
27 int err;
Beniamino Galvanic7757d42016-05-08 08:30:17 +020028
Alexey Romanov7cd53e02023-09-21 11:13:41 +030029 err = uclass_first_device_err(UCLASS_SM, &dev);
30 if (err) {
31 pr_err("Mesom SM device not found\n");
32 return ERR_PTR(err);
33 }
Beniamino Galvanic7757d42016-05-08 08:30:17 +020034
Alexey Romanov7cd53e02023-09-21 11:13:41 +030035 return dev;
Beniamino Galvanic7757d42016-05-08 08:30:17 +020036}
37
38ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size)
39{
Alexey Romanov7cd53e02023-09-21 11:13:41 +030040 struct udevice *dev;
41 struct pt_regs regs = { 0 };
42 int err;
Beniamino Galvanic7757d42016-05-08 08:30:17 +020043
Alexey Romanov7cd53e02023-09-21 11:13:41 +030044 dev = meson_get_sm_device();
45 if (IS_ERR(dev))
46 return PTR_ERR(dev);
Beniamino Galvanic7757d42016-05-08 08:30:17 +020047
Beniamino Galvanic7757d42016-05-08 08:30:17 +020048 regs.regs[1] = offset;
49 regs.regs[2] = size;
50
Alexey Romanov7cd53e02023-09-21 11:13:41 +030051 err = sm_call_read(dev, buffer, size,
52 MESON_SMC_CMD_EFUSE_READ, &regs);
53 if (err < 0)
54 pr_err("Failed to read efuse memory (%d)\n", err);
Beniamino Galvanic7757d42016-05-08 08:30:17 +020055
Alexey Romanov7cd53e02023-09-21 11:13:41 +030056 return err;
Beniamino Galvanic7757d42016-05-08 08:30:17 +020057}
Neil Armstrong0ef8e402019-06-12 11:49:06 +020058
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030059ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size)
60{
Alexey Romanov7cd53e02023-09-21 11:13:41 +030061 struct udevice *dev;
62 struct pt_regs regs = { 0 };
63 int err;
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030064
Alexey Romanov7cd53e02023-09-21 11:13:41 +030065 dev = meson_get_sm_device();
66 if (IS_ERR(dev))
67 return PTR_ERR(dev);
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030068
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030069 regs.regs[1] = offset;
70 regs.regs[2] = size;
71
Alexey Romanov7cd53e02023-09-21 11:13:41 +030072 err = sm_call_write(dev, buffer, size,
73 MESON_SMC_CMD_EFUSE_WRITE, &regs);
74 if (err < 0)
75 pr_err("Failed to write efuse memory (%d)\n", err);
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030076
Alexey Romanov7cd53e02023-09-21 11:13:41 +030077 return err;
Vyacheslav Bocharov52195ba2021-10-05 15:00:03 +030078}
79
Neil Armstrong0ef8e402019-06-12 11:49:06 +020080#define SM_CHIP_ID_LENGTH 119
81#define SM_CHIP_ID_OFFSET 4
82#define SM_CHIP_ID_SIZE 12
83
84int meson_sm_get_serial(void *buffer, size_t size)
85{
Alexey Romanov7cd53e02023-09-21 11:13:41 +030086 struct udevice *dev;
87 struct pt_regs regs = { 0 };
88 u8 id_buffer[SM_CHIP_ID_LENGTH];
89 int err;
Neil Armstrong0ef8e402019-06-12 11:49:06 +020090
Alexey Romanov7cd53e02023-09-21 11:13:41 +030091 dev = meson_get_sm_device();
92 if (IS_ERR(dev))
93 return PTR_ERR(dev);
Neil Armstrong0ef8e402019-06-12 11:49:06 +020094
Alexey Romanov7cd53e02023-09-21 11:13:41 +030095 err = sm_call_read(dev, id_buffer, SM_CHIP_ID_LENGTH,
96 MESON_SMC_CMD_CHIP_ID_GET, &regs);
97 if (err < 0)
98 pr_err("Failed to read serial number (%d)\n", err);
Neil Armstrong0ef8e402019-06-12 11:49:06 +020099
Alexey Romanov7cd53e02023-09-21 11:13:41 +0300100 memcpy(buffer, id_buffer + SM_CHIP_ID_OFFSET, size);
Neil Armstrong0ef8e402019-06-12 11:49:06 +0200101
102 return 0;
103}
Neil Armstrong559e6252019-08-06 17:21:02 +0200104
Neil Armstrongb1dd7de2019-08-06 17:28:36 +0200105#define AO_SEC_SD_CFG15 0xfc
106#define REBOOT_REASON_MASK GENMASK(15, 12)
107
108int meson_sm_get_reboot_reason(void)
109{
110 struct regmap *regmap;
111 int nodeoffset;
112 ofnode node;
113 unsigned int reason;
114
115 /* find the offset of compatible node */
116 nodeoffset = fdt_node_offset_by_compatible(gd->fdt_blob, -1,
117 "amlogic,meson-gx-ao-secure");
118 if (nodeoffset < 0) {
119 printf("%s: failed to get amlogic,meson-gx-ao-secure\n",
120 __func__);
121 return -ENODEV;
122 }
123
124 /* get regmap from the syscon node */
125 node = offset_to_ofnode(nodeoffset);
126 regmap = syscon_node_to_regmap(node);
127 if (IS_ERR(regmap)) {
128 printf("%s: failed to get regmap\n", __func__);
129 return -EINVAL;
130 }
131
132 regmap_read(regmap, AO_SEC_SD_CFG15, &reason);
133
134 /* The SMC call is not used, we directly use AO_SEC_SD_CFG15 */
135 return FIELD_GET(REBOOT_REASON_MASK, reason);
136}
Alexey Romanoveb0a01e2023-05-31 12:31:54 +0300137
138int meson_sm_pwrdm_set(size_t index, int cmd)
139{
Alexey Romanov7cd53e02023-09-21 11:13:41 +0300140 struct udevice *dev;
141 struct pt_regs regs = { 0 };
142 int err;
Alexey Romanoveb0a01e2023-05-31 12:31:54 +0300143
Alexey Romanov7cd53e02023-09-21 11:13:41 +0300144 dev = meson_get_sm_device();
145 if (IS_ERR(dev))
146 return PTR_ERR(dev);
147
Alexey Romanoveb0a01e2023-05-31 12:31:54 +0300148 regs.regs[1] = index;
149 regs.regs[2] = cmd;
150
Alexey Romanov7cd53e02023-09-21 11:13:41 +0300151 err = sm_call(dev, MESON_SMC_CMD_PWRDM_SET, NULL, &regs);
152 if (err)
153 pr_err("Failed to %s power domain ind=%zu (%d)\n", cmd == PWRDM_ON ?
154 "enable" : "disable", index, err);
Alexey Romanoveb0a01e2023-05-31 12:31:54 +0300155
Alexey Romanov7cd53e02023-09-21 11:13:41 +0300156 return err;
Alexey Romanoveb0a01e2023-05-31 12:31:54 +0300157}