1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2024 Linaro Ltd.
4  * Author: Sam Protsenko <semen.protsenko@linaro.org>
5  *
6  * Firmware loading code.
7  */
8 
9 #include <part.h>
10 #include <fs.h>
11 #include <linux/arm-smccc.h>
12 #include "fw.h"
13 
14 #define EMMC_IFACE		"mmc"
15 #define EMMC_DEV_NUM		0
16 #define LDFW_RAW_PART		"ldfw"
17 #define LDFW_FAT_PART		"esp"
18 #define LDFW_FAT_PATH		"/EFI/firmware/ldfw.bin"
19 
20 #define LDFW_NWD_ADDR		0x88000000
21 #define LDFW_MAGIC		0x10adab1e
22 #define SMC_CMD_LOAD_LDFW	-0x500
23 #define SDM_HW_RESET_STATUS	0x1230
24 #define SDM_SW_RESET_STATUS	0x1231
25 #define SB_ERROR_PREFIX		0xfdaa0000
26 
27 struct ldfw_header {
28 	u32 magic;
29 	u32 size;
30 	u32 init_entry;
31 	u32 entry_point;
32 	u32 suspend_entry;
33 	u32 resume_entry;
34 	u32 start_smc_id;
35 	u32 version;
36 	u32 set_runtime_entry;
37 	u32 reserved[3];
38 	char fw_name[16];
39 };
40 
41 /* Load LDFW binary as a file from FAT partition */
read_fw_from_fat(const char * part_name,const char * path,void * buf)42 static int read_fw_from_fat(const char *part_name, const char *path, void *buf)
43 {
44 	char dev_part_str[8];
45 	loff_t len_read;
46 	int err;
47 
48 	snprintf(dev_part_str, sizeof(dev_part_str), "%d#%s", EMMC_DEV_NUM,
49 		 LDFW_FAT_PART);
50 
51 	err = fs_set_blk_dev(EMMC_IFACE, dev_part_str, FS_TYPE_FAT);
52 	if (err) {
53 		debug("%s: Can't set block device\n", __func__);
54 		return -ENODEV;
55 	}
56 
57 	err = fs_read(path, (ulong)buf, 0, 0, &len_read);
58 	if (err) {
59 		debug("%s: Can't read LDFW file\n", __func__);
60 		return -EIO;
61 	}
62 
63 	return 0;
64 }
65 
66 /* Load LDFW binary from raw partition on block device into RAM buffer */
read_fw_from_raw(const char * part_name,void * buf)67 static int read_fw_from_raw(const char *part_name, void *buf)
68 {
69 	struct blk_desc *blk_desc;
70 	struct disk_partition part;
71 	unsigned long cnt;
72 	int part_num;
73 
74 	blk_desc = blk_get_dev(EMMC_IFACE, EMMC_DEV_NUM);
75 	if (!blk_desc) {
76 		debug("%s: Can't get eMMC device\n", __func__);
77 		return -ENODEV;
78 	}
79 
80 	part_num = part_get_info_by_name(blk_desc, part_name, &part);
81 	if (part_num < 0) {
82 		debug("%s: Can't get LDWF partition\n", __func__);
83 		return -ENOENT;
84 	}
85 
86 	cnt = blk_dread(blk_desc, part.start, part.size, buf);
87 	if (cnt != part.size) {
88 		debug("%s: Can't read LDFW partition\n", __func__);
89 		return -EIO;
90 	}
91 
92 	return 0;
93 }
94 
load_ldfw(void)95 int load_ldfw(void)
96 {
97 	const phys_addr_t addr = (phys_addr_t)LDFW_NWD_ADDR;
98 	struct ldfw_header *hdr;
99 	struct arm_smccc_res res;
100 	void *buf = (void *)addr;
101 	u64 size = 0;
102 	int err, i;
103 
104 	/* First try to read LDFW from EFI partition, then from the raw one */
105 	err = read_fw_from_fat(LDFW_FAT_PART, LDFW_FAT_PATH, buf);
106 	if (err) {
107 		err = read_fw_from_raw(LDFW_RAW_PART, buf);
108 		if (err)
109 			return err;
110 	}
111 
112 	/* Validate LDFW by magic number in its header */
113 	hdr = buf;
114 	if (hdr->magic != LDFW_MAGIC) {
115 		debug("%s: Wrong LDFW magic; is LDFW flashed?\n", __func__);
116 		return -EINVAL;
117 	}
118 
119 	/* Calculate actual total size of all LDFW blobs */
120 	for (i = 0; hdr->magic == LDFW_MAGIC; ++i) {
121 #ifdef DEBUG
122 		char name[17] = { 0 };
123 
124 		strncpy(name, hdr->fw_name, 16);
125 		debug("%s: ldfw #%d: version = 0x%x, name = %s\n", __func__, i,
126 		      hdr->version, name);
127 #endif
128 
129 		size += (u64)hdr->size;
130 		hdr = (struct ldfw_header *)((u64)hdr + (u64)hdr->size);
131 	}
132 	debug("%s: The whole size of all LDFWs: 0x%llx\n", __func__, size);
133 
134 	/* Load LDFW firmware to SWD (Secure World) memory via EL3 monitor */
135 	arm_smccc_smc(SMC_CMD_LOAD_LDFW, addr, size, 0, 0, 0, 0, 0, &res);
136 	err = (int)res.a0;
137 	if (err == -1 || err == SDM_HW_RESET_STATUS) {
138 		debug("%s: Can't load LDFW in dump_gpr state\n", __func__);
139 		return -EIO;
140 	} else if (err == SDM_SW_RESET_STATUS) {
141 		debug("%s: Can't load LDFW in kernel panic (SW RESET) state\n",
142 		      __func__);
143 		return -EIO;
144 	} else if (err < 0 && (err & 0xffff0000) == SB_ERROR_PREFIX) {
145 		debug("%s: LDFW signature is corrupted! ret=0x%x\n", __func__,
146 		      (u32)err);
147 		return -EIO;
148 	} else if (err == 0) {
149 		debug("%s: No LDFW is inited\n", __func__);
150 		return -EIO;
151 	}
152 
153 #ifdef DEBUG
154 	u32 tried = res.a0 & 0xffff;
155 	u32 failed = (res.a0 >> 16) & 0xffff;
156 
157 	debug("%s: %d/%d LDFWs have been loaded successfully\n", __func__,
158 	      tried - failed, tried);
159 #endif
160 
161 	return 0;
162 }
163