1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2016 Beniamino Galvani <b.galvani@gmail.com> 4 * 5 * Secure monitor calls. 6 */ 7 8#include <common.h> 9#include <dm.h> 10#include <log.h> 11#include <regmap.h> 12#include <sm.h> 13#include <syscon.h> 14#include <asm/arch/sm.h> 15#include <asm/cache.h> 16#include <asm/global_data.h> 17#include <asm/ptrace.h> 18#include <linux/bitops.h> 19#include <linux/err.h> 20#include <linux/kernel.h> 21#include <linux/bitfield.h> 22#include <meson/sm.h> 23 24static inline struct udevice *meson_get_sm_device(void) 25{ 26 struct udevice *dev; 27 int err; 28 29 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 } 34 35 return dev; 36} 37 38ssize_t meson_sm_read_efuse(uintptr_t offset, void *buffer, size_t size) 39{ 40 struct udevice *dev; 41 struct pt_regs regs = { 0 }; 42 int err; 43 44 dev = meson_get_sm_device(); 45 if (IS_ERR(dev)) 46 return PTR_ERR(dev); 47 48 regs.regs[1] = offset; 49 regs.regs[2] = size; 50 51 err = sm_call_read(dev, buffer, size, 52 MESON_SMC_CMD_EFUSE_READ, ®s); 53 if (err < 0) 54 pr_err("Failed to read efuse memory (%d)\n", err); 55 56 return err; 57} 58 59ssize_t meson_sm_write_efuse(uintptr_t offset, void *buffer, size_t size) 60{ 61 struct udevice *dev; 62 struct pt_regs regs = { 0 }; 63 int err; 64 65 dev = meson_get_sm_device(); 66 if (IS_ERR(dev)) 67 return PTR_ERR(dev); 68 69 regs.regs[1] = offset; 70 regs.regs[2] = size; 71 72 err = sm_call_write(dev, buffer, size, 73 MESON_SMC_CMD_EFUSE_WRITE, ®s); 74 if (err < 0) 75 pr_err("Failed to write efuse memory (%d)\n", err); 76 77 return err; 78} 79 80#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{ 86 struct udevice *dev; 87 struct pt_regs regs = { 0 }; 88 u8 id_buffer[SM_CHIP_ID_LENGTH]; 89 int err; 90 91 dev = meson_get_sm_device(); 92 if (IS_ERR(dev)) 93 return PTR_ERR(dev); 94 95 err = sm_call_read(dev, id_buffer, SM_CHIP_ID_LENGTH, 96 MESON_SMC_CMD_CHIP_ID_GET, ®s); 97 if (err < 0) 98 pr_err("Failed to read serial number (%d)\n", err); 99 100 memcpy(buffer, id_buffer + SM_CHIP_ID_OFFSET, size); 101 102 return 0; 103} 104 105#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} 137 138int meson_sm_pwrdm_set(size_t index, int cmd) 139{ 140 struct udevice *dev; 141 struct pt_regs regs = { 0 }; 142 int err; 143 144 dev = meson_get_sm_device(); 145 if (IS_ERR(dev)) 146 return PTR_ERR(dev); 147 148 regs.regs[1] = index; 149 regs.regs[2] = cmd; 150 151 err = sm_call(dev, MESON_SMC_CMD_PWRDM_SET, NULL, ®s); 152 if (err) 153 pr_err("Failed to %s power domain ind=%zu (%d)\n", cmd == PWRDM_ON ? 154 "enable" : "disable", index, err); 155 156 return err; 157} 158