1 /* 2 * Load Analog Devices SigmaStudio firmware files 3 * 4 * Copyright 2009-2011 Analog Devices Inc. 5 * 6 * Licensed under the GPL-2 or later. 7 */ 8 9 #include <linux/crc32.h> 10 #include <linux/delay.h> 11 #include <linux/firmware.h> 12 #include <linux/kernel.h> 13 #include <linux/i2c.h> 14 #include <linux/regmap.h> 15 #include <linux/module.h> 16 17 #include "sigmadsp.h" 18 19 #define SIGMA_MAGIC "ADISIGM" 20 21 struct sigma_firmware_header { 22 unsigned char magic[7]; 23 u8 version; 24 __le32 crc; 25 } __packed; 26 27 enum { 28 SIGMA_ACTION_WRITEXBYTES = 0, 29 SIGMA_ACTION_WRITESINGLE, 30 SIGMA_ACTION_WRITESAFELOAD, 31 SIGMA_ACTION_DELAY, 32 SIGMA_ACTION_PLLWAIT, 33 SIGMA_ACTION_NOOP, 34 SIGMA_ACTION_END, 35 }; 36 37 static inline u32 sigma_action_len(struct sigma_action *sa) 38 { 39 return (sa->len_hi << 16) | le16_to_cpu(sa->len); 40 } 41 42 static size_t sigma_action_size(struct sigma_action *sa) 43 { 44 size_t payload = 0; 45 46 switch (sa->instr) { 47 case SIGMA_ACTION_WRITEXBYTES: 48 case SIGMA_ACTION_WRITESINGLE: 49 case SIGMA_ACTION_WRITESAFELOAD: 50 payload = sigma_action_len(sa); 51 break; 52 default: 53 break; 54 } 55 56 payload = ALIGN(payload, 2); 57 58 return payload + sizeof(struct sigma_action); 59 } 60 61 /* 62 * Returns a negative error value in case of an error, 0 if processing of 63 * the firmware should be stopped after this action, 1 otherwise. 64 */ 65 static int 66 process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) 67 { 68 size_t len = sigma_action_len(sa); 69 int ret; 70 71 pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, 72 sa->instr, sa->addr, len); 73 74 switch (sa->instr) { 75 case SIGMA_ACTION_WRITEXBYTES: 76 case SIGMA_ACTION_WRITESINGLE: 77 case SIGMA_ACTION_WRITESAFELOAD: 78 ret = ssfw->write(ssfw->control_data, sa, len); 79 if (ret < 0) 80 return -EINVAL; 81 break; 82 case SIGMA_ACTION_DELAY: 83 udelay(len); 84 len = 0; 85 break; 86 case SIGMA_ACTION_END: 87 return 0; 88 default: 89 return -EINVAL; 90 } 91 92 return 1; 93 } 94 95 static int 96 process_sigma_actions(struct sigma_firmware *ssfw) 97 { 98 struct sigma_action *sa; 99 size_t size; 100 int ret; 101 102 while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { 103 sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); 104 105 size = sigma_action_size(sa); 106 ssfw->pos += size; 107 if (ssfw->pos > ssfw->fw->size || size == 0) 108 break; 109 110 ret = process_sigma_action(ssfw, sa); 111 112 pr_debug("%s: action returned %i\n", __func__, ret); 113 114 if (ret <= 0) 115 return ret; 116 } 117 118 if (ssfw->pos != ssfw->fw->size) 119 return -EINVAL; 120 121 return 0; 122 } 123 124 int _process_sigma_firmware(struct device *dev, 125 struct sigma_firmware *ssfw, const char *name) 126 { 127 int ret; 128 struct sigma_firmware_header *ssfw_head; 129 const struct firmware *fw; 130 u32 crc; 131 132 pr_debug("%s: loading firmware %s\n", __func__, name); 133 134 /* first load the blob */ 135 ret = request_firmware(&fw, name, dev); 136 if (ret) { 137 pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); 138 return ret; 139 } 140 ssfw->fw = fw; 141 142 /* then verify the header */ 143 ret = -EINVAL; 144 145 /* 146 * Reject too small or unreasonable large files. The upper limit has been 147 * chosen a bit arbitrarily, but it should be enough for all practical 148 * purposes and having the limit makes it easier to avoid integer 149 * overflows later in the loading process. 150 */ 151 if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { 152 dev_err(dev, "Failed to load firmware: Invalid size\n"); 153 goto done; 154 } 155 156 ssfw_head = (void *)fw->data; 157 if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { 158 dev_err(dev, "Failed to load firmware: Invalid magic\n"); 159 goto done; 160 } 161 162 crc = crc32(0, fw->data + sizeof(*ssfw_head), 163 fw->size - sizeof(*ssfw_head)); 164 pr_debug("%s: crc=%x\n", __func__, crc); 165 if (crc != le32_to_cpu(ssfw_head->crc)) { 166 dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", 167 le32_to_cpu(ssfw_head->crc), crc); 168 goto done; 169 } 170 171 ssfw->pos = sizeof(*ssfw_head); 172 173 /* finally process all of the actions */ 174 ret = process_sigma_actions(ssfw); 175 176 done: 177 release_firmware(fw); 178 179 pr_debug("%s: loaded %s\n", __func__, name); 180 181 return ret; 182 } 183 EXPORT_SYMBOL_GPL(_process_sigma_firmware); 184 185 MODULE_LICENSE("GPL"); 186