1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (c) 2017-2026 Morse Micro 4 */ 5 #include <linux/firmware.h> 6 #include <linux/delay.h> 7 #include <linux/stringify.h> 8 #include <linux/types.h> 9 #include <linux/unaligned.h> 10 #include <linux/gpio.h> 11 #include "hif.h" 12 #include "mac.h" 13 #include "bus.h" 14 #include "core.h" 15 #include "fw.h" 16 #include "yaps.h" 17 18 #define MM8108_REG_HOST_MAGIC_VALUE 0xDEADBEEF 19 #define MM8108_REG_RESET_VALUE 0xDEAD 20 21 #define MM8108_REG_SDIO_DEVICE_ADDR 0x0000207C 22 23 #define MM8108_REG_SDIO_DEVICE_BURST_OFFSET 9 24 #define MM8108_REG_TRGR_BASE 0x00003c00 25 #define MM8108_REG_INT_BASE 0x00003c50 26 #define MM8108_REG_MSI_ADDRESS 0x00004100 27 #define MM8108_REG_MSI_VALUE 0x1 28 #define MM8108_REG_MANIFEST_PTR_ADDRESS 0x00002d40 29 #define MM8108_REG_APPS_BOOT_ADDR 0x00002084 30 #define MM8108_REG_RESET 0x000020AC 31 #define MM8108_REG_AON_COUNT 2 32 33 #define MM8108_REG_AON_ADDR 0x00002114 34 #define MM8108_REG_AON_LATCH_ADDR 0x00405020 35 #define MM8108_REG_AON_LATCH_MASK 0x1 36 #define MM8108_REG_AON_RESET_USB_VALUE 0x8 37 #define MM8108_APPS_MAC_DMEM_ADDR_START 0x00100000 38 39 #define MM8108_REG_RC_CLK_POWER_OFF_ADDR 0x00405020 40 #define MM8108_REG_RC_CLK_POWER_OFF_MASK 0x00000040 41 #define MM8108_SLOW_RC_POWER_ON_DELAY_MS 2 42 43 #define MM8108_RESET_DELAY_TIME_MS 400 44 45 #define MM8108_REG_OTPCTRL_PLDO 0x00004014 46 #define MM8108_REG_OTPCTRL_PENVDD2 0x00004010 47 #define MM8108_REG_OTPCTRL_PDSTB 0x00004018 48 #define MM8108_REG_OTPCTRL_PTM 0x0000401c 49 #define MM8108_REG_OTPCTRL_PCE 0x00004020 50 #define MM8108_REG_OTPCTRL_PA 0x00004034 51 #define MM8108_REG_OTPCTRL_PECCRDB 0x00004048 52 #define MM8108_REG_OTPCTRL_ACTION_AUTO_RD_START 0x0000400c 53 #define MM8108_REG_OTPCTRL_PDOUT 0x00004040 54 55 #define MM81X_OTP_MAC_ADDR_2_BANK_NUM 27 56 #define MM81X_OTP_MAC_ADDR_1_BANK_NUM 26 57 #define MM81X_OTP_MAC_ADDR_1_MASK GENMASK(31, 16) 58 #define MM81X_OTP_BOARD_TYPE_BANK_NUM 26 59 #define MM81X_OTP_BOARD_TYPE_MASK GENMASK(15, 0) 60 61 #define MM810X_BOARD_TYPE_MAX_VALUE (MM81X_OTP_BOARD_TYPE_MASK - 1) 62 63 static void mm81x_hw_otp_power_up(struct mm81x *mors) 64 { 65 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PENVDD2, 1); 66 udelay(2); 67 68 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PLDO, 1); 69 usleep_range(10, 20); 70 71 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PDSTB, 1); 72 udelay(3); 73 } 74 75 static void mm81x_hw_otp_power_down(struct mm81x *mors) 76 { 77 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PDSTB, 0); 78 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PLDO, 0); 79 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PENVDD2, 0); 80 } 81 82 static void mm81x_hw_otp_read_enable(struct mm81x *mors) 83 { 84 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PTM, 0); 85 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PCE, 1); 86 usleep_range(10, 20); 87 } 88 89 static void mm81x_hw_otp_read_disable(struct mm81x *mors) 90 { 91 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PCE, 0); 92 udelay(1); 93 } 94 95 static int mm81x_hw_otp_read(struct mm81x *mors, u8 bank_num, u32 *buf, 96 u8 ignore_ecc) 97 { 98 u32 auto_rd_start_tmp; 99 u32 auto_rd_start = 1; 100 int i; 101 102 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PA, bank_num); 103 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_PECCRDB, ignore_ecc); 104 105 mm81x_reg32_read(mors, MM8108_REG_OTPCTRL_ACTION_AUTO_RD_START, 106 &auto_rd_start_tmp); 107 auto_rd_start_tmp &= 0xfffffffe; 108 109 mm81x_reg32_write(mors, MM8108_REG_OTPCTRL_ACTION_AUTO_RD_START, 110 auto_rd_start | auto_rd_start_tmp); 111 112 /* Attempt reading up to 5 times. */ 113 for (i = 0; i < 5 && auto_rd_start; i++) { 114 usleep_range(15, 20); 115 mm81x_reg32_read(mors, MM8108_REG_OTPCTRL_ACTION_AUTO_RD_START, 116 &auto_rd_start_tmp); 117 auto_rd_start = auto_rd_start_tmp & 0x1; 118 } 119 120 if (i == 5) 121 return -EIO; 122 123 mm81x_reg32_read(mors, MM8108_REG_OTPCTRL_PDOUT, buf); 124 125 return 0; 126 } 127 128 int mm81x_hw_otp_get_board_type(struct mm81x *mors) 129 { 130 int board_type = 0; 131 u32 otp_word = 0; 132 int ret; 133 134 mm81x_claim_bus(mors); 135 mm81x_hw_otp_power_up(mors); 136 mm81x_hw_otp_read_enable(mors); 137 138 ret = mm81x_hw_otp_read(mors, MM81X_OTP_BOARD_TYPE_BANK_NUM, &otp_word, 139 1); 140 141 mm81x_hw_otp_read_disable(mors); 142 mm81x_hw_otp_power_down(mors); 143 mm81x_release_bus(mors); 144 145 if (ret) 146 return -EINVAL; 147 148 board_type = otp_word & MM81X_OTP_BOARD_TYPE_MASK; 149 150 return board_type; 151 } 152 153 bool mm81x_hw_otp_valid_board_type(u32 board_type) 154 { 155 return board_type > 0 && board_type < MM810X_BOARD_TYPE_MAX_VALUE; 156 } 157 158 int mm81x_hw_otp_get_mac_addr(struct mm81x *mors) 159 { 160 u32 mac1 = 0; 161 u32 mac2 = 0; 162 int ret = 0; 163 164 mm81x_claim_bus(mors); 165 mm81x_hw_otp_power_up(mors); 166 mm81x_hw_otp_read_enable(mors); 167 168 ret = mm81x_hw_otp_read(mors, MM81X_OTP_MAC_ADDR_1_BANK_NUM, &mac1, 1); 169 if (ret) 170 goto exit; 171 172 ret = mm81x_hw_otp_read(mors, MM81X_OTP_MAC_ADDR_2_BANK_NUM, &mac2, 1); 173 if (ret) 174 goto exit; 175 176 put_unaligned_le16((mac1 & MM81X_OTP_MAC_ADDR_1_MASK) >> 16, 177 &mors->macaddr[0]); 178 put_unaligned_le32(mac2, &mors->macaddr[2]); 179 180 exit: 181 mm81x_hw_otp_read_disable(mors); 182 mm81x_hw_otp_power_down(mors); 183 mm81x_release_bus(mors); 184 185 return ret; 186 } 187 188 void mm81x_hw_irq_enable(struct mm81x *mors, u32 irq, bool enable) 189 { 190 u32 irq_en, irq_en_addr = irq < 32 ? MM81X_REG_INT1_EN(mors) : 191 MM81X_REG_INT2_EN(mors); 192 u32 irq_clr_addr = irq < 32 ? MM81X_REG_INT1_CLR(mors) : 193 MM81X_REG_INT2_CLR(mors); 194 u32 mask = irq < 32 ? (1 << irq) : (1 << (irq - 32)); 195 196 mm81x_claim_bus(mors); 197 mm81x_reg32_read(mors, irq_en_addr, &irq_en); 198 if (enable) 199 irq_en |= (mask); 200 else 201 irq_en &= ~(mask); 202 mm81x_reg32_write(mors, irq_clr_addr, mask); 203 mm81x_reg32_write(mors, irq_en_addr, irq_en); 204 mm81x_release_bus(mors); 205 } 206 207 int mm81x_hw_irq_handle(struct mm81x *mors) 208 { 209 u32 status1 = 0; 210 211 mm81x_reg32_read(mors, MM81X_REG_INT1_STS(mors), &status1); 212 213 if (status1 & MM81X_HIF_IRQ_MASK_ALL) 214 mm81x_hif_handle_irq(mors, status1); 215 216 if (status1 & MM81X_INT_BEACON_VIF_MASK_ALL) 217 mm81x_mac_beacon_irq_handle(mors, status1); 218 219 mm81x_reg32_write(mors, MM81X_REG_INT1_CLR(mors), status1); 220 221 return status1 ? 1 : 0; 222 } 223 EXPORT_SYMBOL_GPL(mm81x_hw_irq_handle); 224 225 void mm81x_hw_irq_clear(struct mm81x *mors) 226 { 227 mm81x_claim_bus(mors); 228 mm81x_reg32_write(mors, MM81X_REG_INT1_CLR(mors), 0xFFFFFFFF); 229 mm81x_reg32_write(mors, MM81X_REG_INT2_CLR(mors), 0xFFFFFFFF); 230 mm81x_release_bus(mors); 231 } 232 233 void mm81x_hw_toggle_aon_latch(struct mm81x *mors) 234 { 235 u32 address = MM81X_REG_AON_LATCH_ADDR(mors); 236 u32 mask = MM81X_REG_AON_LATCH_MASK(mors); 237 u32 latch; 238 239 mm81x_reg32_read(mors, address, &latch); 240 mm81x_reg32_write(mors, address, latch & ~(mask)); 241 mdelay(5); 242 mm81x_reg32_write(mors, address, latch | mask); 243 mdelay(5); 244 mm81x_reg32_write(mors, address, latch & ~(mask)); 245 mdelay(5); 246 } 247 248 void mm81x_hw_enable_stop_notifications(struct mm81x *mors, bool enable) 249 { 250 mm81x_hw_irq_enable(mors, MM81X_INT_HW_STOP_NOTIFICATION_NUM, enable); 251 } 252 253 void mm81x_hw_enable_burst_mode(struct mm81x *mors, const u8 burst_mode) 254 { 255 u32 reg32_value; 256 257 mm81x_claim_bus(mors); 258 if (mm81x_reg32_read(mors, MM8108_REG_SDIO_DEVICE_ADDR, ®32_value)) 259 goto end; 260 261 reg32_value &= ~(u32)(SDIO_WORD_BURST_MASK 262 << MM8108_REG_SDIO_DEVICE_BURST_OFFSET); 263 reg32_value |= (u32)(burst_mode << MM8108_REG_SDIO_DEVICE_BURST_OFFSET); 264 265 dev_dbg(mors->dev, 266 "Setting Burst mode to %d Writing 0x%08X to the register", 267 burst_mode, reg32_value); 268 269 if (mm81x_reg32_write(mors, MM8108_REG_SDIO_DEVICE_ADDR, reg32_value)) 270 goto end; 271 272 end: 273 mm81x_release_bus(mors); 274 } 275 EXPORT_SYMBOL_GPL(mm81x_hw_enable_burst_mode); 276 277 static int mm81x_hw_enable_internal_slow_clock(struct mm81x *mors) 278 { 279 u32 rc_clock_reg_value; 280 int ret = 0; 281 282 dev_dbg(mors->dev, "Enabling internal slow clock"); 283 284 ret = mm81x_reg32_read(mors, MM8108_REG_RC_CLK_POWER_OFF_ADDR, 285 &rc_clock_reg_value); 286 if (ret) 287 goto exit; 288 289 rc_clock_reg_value &= ~MM8108_REG_RC_CLK_POWER_OFF_MASK; 290 ret = mm81x_reg32_write(mors, MM8108_REG_RC_CLK_POWER_OFF_ADDR, 291 rc_clock_reg_value); 292 if (ret) 293 goto exit; 294 295 mm81x_hw_toggle_aon_latch(mors); 296 297 /* Wait for the clock to turn on and settle */ 298 mdelay(MM8108_SLOW_RC_POWER_ON_DELAY_MS); 299 exit: 300 return ret; 301 } 302 303 int mm81x_hw_digital_reset(struct mm81x *mors) 304 { 305 int ret = 0; 306 307 mm81x_claim_bus(mors); 308 309 /* This should be the first step in digital reset, do not reorder */ 310 ret = mm81x_hw_enable_internal_slow_clock(mors); 311 if (ret) 312 goto exit; 313 314 if (mors->bus_type == MM81X_BUS_TYPE_USB) { 315 ret = mm81x_bus_digital_reset(mors); 316 goto usb_done; 317 } 318 319 if (MM81X_REG_RESET(mors) != 0) 320 ret = mm81x_reg32_write(mors, MM81X_REG_RESET(mors), 321 MM81X_REG_RESET_VALUE(mors)); 322 323 usb_done: 324 msleep(MM8108_RESET_DELAY_TIME_MS); 325 exit: 326 mm81x_release_bus(mors); 327 328 if (!ret) 329 mors->chip_was_reset = true; 330 331 return ret; 332 } 333 334 void mm81x_hw_pre_firmware_ndr_hook(struct mm81x *mors) 335 { 336 /* We need disable bursting for firmware download/init procedure */ 337 mm81x_bus_config_burst_mode(mors, false); 338 } 339 340 void mm81x_hw_post_firmware_ndr_hook(struct mm81x *mors) 341 { 342 /* We are safe here to re-enable bursting again, if supported */ 343 mm81x_bus_config_burst_mode(mors, true); 344 } 345 346 const struct mm81x_regs mm8108_regs = { 347 .chip_id_address = MM8108_REG_CHIP_ID, 348 .irq_base_address = MM8108_REG_INT_BASE, 349 .trgr_base_address = MM8108_REG_TRGR_BASE, 350 .cpu_reset_address = MM8108_REG_RESET, 351 .cpu_reset_value = MM8108_REG_RESET_VALUE, 352 .manifest_ptr_address = MM8108_REG_MANIFEST_PTR_ADDRESS, 353 .msi_address = MM8108_REG_MSI_ADDRESS, 354 .msi_value = MM8108_REG_MSI_VALUE, 355 .magic_num_value = MM8108_REG_HOST_MAGIC_VALUE, 356 .early_clk_ctrl_value = 0, 357 .pager_base_address = MM8108_APPS_MAC_DMEM_ADDR_START, 358 .aon_latch = MM8108_REG_AON_LATCH_ADDR, 359 .aon_latch_mask = MM8108_REG_AON_LATCH_MASK, 360 .aon_reset_usb_value = MM8108_REG_AON_RESET_USB_VALUE, 361 .aon = MM8108_REG_AON_ADDR, 362 .aon_count = MM8108_REG_AON_COUNT, 363 .boot_address = MM8108_REG_APPS_BOOT_ADDR, 364 }; 365 366 MODULE_FIRMWARE(MM81X_FW_DIR "/v" __stringify(MM81X_FW_VER_MAX) "/" 367 MM8108_FW_BASE MM81X_FW_EXT); 368