1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * sbrmi-core.c - file defining SB-RMI protocols compliant 4 * AMD SoC device. 5 * 6 * Copyright (C) 2025 Advanced Micro Devices, Inc. 7 */ 8 #include <linux/delay.h> 9 #include <linux/err.h> 10 #include <linux/fs.h> 11 #include <linux/i2c.h> 12 #include <linux/miscdevice.h> 13 #include <linux/module.h> 14 #include <linux/mutex.h> 15 #include <linux/regmap.h> 16 #include "rmi-core.h" 17 18 /* Mask for Status Register bit[1] */ 19 #define SW_ALERT_MASK 0x2 20 /* Mask to check H/W Alert status bit */ 21 #define HW_ALERT_MASK 0x80 22 23 /* Software Interrupt for triggering */ 24 #define START_CMD 0x80 25 #define TRIGGER_MAILBOX 0x01 26 27 /* Default message lengths as per APML command protocol */ 28 /* CPUID */ 29 #define CPUID_RD_DATA_LEN 0x8 30 #define CPUID_WR_DATA_LEN 0x8 31 #define CPUID_WR_DATA_LEN_EXT 0x9 32 #define CPUID_RD_REG_LEN 0xa 33 #define CPUID_WR_REG_LEN 0x9 34 #define CPUID_WR_REG_LEN_EXT 0xa 35 /* MSR */ 36 #define MSR_RD_REG_LEN 0xa 37 #define MSR_WR_REG_LEN 0x8 38 #define MSR_WR_REG_LEN_EXT 0x9 39 #define MSR_RD_DATA_LEN 0x8 40 #define MSR_WR_DATA_LEN 0x7 41 #define MSR_WR_DATA_LEN_EXT 0x8 42 43 /* CPUID MSR Command Ids */ 44 #define CPUID_MCA_CMD 0x73 45 #define RD_CPUID_CMD 0x91 46 #define RD_MCA_CMD 0x86 47 48 /* CPUID MCAMSR mask & index */ 49 #define CPUID_MCA_THRD_INDEX 32 50 #define CPUID_MCA_FUNC_MASK GENMASK(31, 0) 51 #define CPUID_EXT_FUNC_INDEX 48 52 53 /* input for bulk write to CPUID protocol */ 54 struct cpu_msr_indata { 55 u8 wr_len; /* const value */ 56 u8 rd_len; /* const value */ 57 u8 proto_cmd; /* const value */ 58 u8 thread; /* thread number */ 59 union { 60 u8 reg_offset[4]; /* input value */ 61 u32 value; 62 } __packed; 63 u8 ext; /* extended function */ 64 }; 65 66 /* input for bulk write to CPUID protocol for REV 0x21 */ 67 struct cpu_msr_indata_ext { 68 u8 wr_len; /* const value */ 69 u8 rd_len; /* const value */ 70 u8 proto_cmd; /* const value */ 71 u8 thread_lo; /* thread number low */ 72 u8 thread_hi; /* thread number high */ 73 union { 74 u8 reg_offset[4]; /* input value */ 75 u32 value; 76 } __packed; 77 u8 ext; /* extended function */ 78 }; 79 80 /* output for bulk read from CPUID protocol */ 81 struct cpu_msr_outdata { 82 u8 num_bytes; /* number of bytes return */ 83 u8 status; /* Protocol status code */ 84 union { 85 u64 value; 86 u8 reg_data[8]; 87 } __packed; 88 }; 89 90 static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input, 91 u8 thread_id, u32 func, 92 u8 ext_func) 93 { 94 input->rd_len = CPUID_RD_DATA_LEN; 95 input->wr_len = CPUID_WR_DATA_LEN; 96 input->proto_cmd = RD_CPUID_CMD; 97 input->thread = thread_id << 1; 98 input->value = func; 99 input->ext = ext_func; 100 } 101 102 static inline void prepare_cpuid_input_message_ext(struct cpu_msr_indata_ext *input, 103 u16 thread_id, u32 func, 104 u8 ext_func) 105 { 106 input->rd_len = CPUID_RD_DATA_LEN; 107 input->wr_len = CPUID_WR_DATA_LEN_EXT; 108 input->proto_cmd = RD_CPUID_CMD; 109 input->thread_lo = (thread_id & 0xFF) << 1; 110 input->thread_hi = thread_id >> 8; 111 input->value = func; 112 input->ext = ext_func; 113 } 114 115 static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input, 116 u8 thread_id, u32 data_in) 117 { 118 input->rd_len = MSR_RD_DATA_LEN; 119 input->wr_len = MSR_WR_DATA_LEN; 120 input->proto_cmd = RD_MCA_CMD; 121 input->thread = thread_id << 1; 122 input->value = data_in; 123 } 124 125 static inline void prepare_mca_msr_input_message_ext(struct cpu_msr_indata_ext *input, 126 u16 thread_id, u32 data_in) 127 { 128 input->rd_len = MSR_RD_DATA_LEN; 129 input->wr_len = MSR_WR_DATA_LEN_EXT; 130 input->proto_cmd = RD_MCA_CMD; 131 input->thread_lo = (thread_id & 0xFF) << 1; 132 input->thread_hi = thread_id >> 8; 133 input->value = data_in; 134 } 135 136 static int sbrmi_get_rev(struct sbrmi_data *data) 137 { 138 unsigned int rev; 139 u16 offset = SBRMI_REV; 140 int ret; 141 142 ret = regmap_read(data->regmap, offset, &rev); 143 if (ret < 0) 144 return ret; 145 146 data->rev = rev; 147 return 0; 148 } 149 150 static int rmi_cpuid_input(struct sbrmi_data *data, struct apml_cpuid_msg *msg, 151 u16 thread) 152 { 153 struct cpu_msr_indata input = {0}; 154 int val = 0, ret; 155 156 /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ 157 if (thread > 127) { 158 thread -= 128; 159 val = 1; 160 } 161 162 ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); 163 if (ret < 0) 164 return ret; 165 166 prepare_cpuid_input_message(&input, thread, 167 msg->cpu_in_out & CPUID_MCA_FUNC_MASK, 168 msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX); 169 170 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 171 &input, CPUID_WR_REG_LEN); 172 } 173 174 static int rmi_cpuid_input_ext(struct sbrmi_data *data, struct apml_cpuid_msg *msg, 175 u16 thread) 176 { 177 struct cpu_msr_indata_ext input = {0}; 178 179 prepare_cpuid_input_message_ext(&input, thread, 180 msg->cpu_in_out & CPUID_MCA_FUNC_MASK, 181 msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX); 182 183 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 184 &input, CPUID_WR_REG_LEN_EXT); 185 } 186 187 /* Read CPUID function protocol */ 188 static int rmi_cpuid_read(struct sbrmi_data *data, 189 struct apml_cpuid_msg *msg) 190 { 191 struct cpu_msr_outdata output = {0}; 192 int ret, hw_status; 193 u16 thread; 194 195 mutex_lock(&data->lock); 196 /* cache the rev value to identify if protocol is supported or not */ 197 if (!data->rev) { 198 ret = sbrmi_get_rev(data); 199 if (ret < 0) 200 goto exit_unlock; 201 } 202 203 /* Extract thread from the input msg structure */ 204 thread = msg->cpu_in_out >> CPUID_MCA_THRD_INDEX; 205 206 switch (data->rev) { 207 case 0x10: 208 /* CPUID protocol for REV 0x10 is not supported*/ 209 ret = -EOPNOTSUPP; 210 goto exit_unlock; 211 case 0x20: 212 ret = rmi_cpuid_input(data, msg, thread); 213 if (ret) 214 goto exit_unlock; 215 break; 216 case 0x21: 217 case 0x31: 218 ret = rmi_cpuid_input_ext(data, msg, thread); 219 if (ret) 220 goto exit_unlock; 221 break; 222 default: 223 ret = -EOPNOTSUPP; 224 goto exit_unlock; 225 } 226 227 /* 228 * For RMI Rev 0x20, new h/w status bit is introduced. which is used 229 * by firmware to indicate completion of commands (0x71, 0x72, 0x73). 230 * wait for the status bit to be set by the hardware before 231 * reading the data out. 232 */ 233 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, 234 hw_status & HW_ALERT_MASK, 500, 2000000); 235 if (ret) 236 goto exit_unlock; 237 238 ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, 239 &output, CPUID_RD_REG_LEN); 240 if (ret < 0) 241 goto exit_unlock; 242 243 ret = regmap_write(data->regmap, SBRMI_STATUS, 244 HW_ALERT_MASK); 245 if (ret < 0) 246 goto exit_unlock; 247 248 if (output.num_bytes != CPUID_RD_REG_LEN - 1) { 249 ret = -EMSGSIZE; 250 goto exit_unlock; 251 } 252 if (output.status) { 253 ret = -EPROTOTYPE; 254 msg->fw_ret_code = output.status; 255 goto exit_unlock; 256 } 257 msg->cpu_in_out = output.value; 258 exit_unlock: 259 if (ret < 0) 260 msg->cpu_in_out = 0; 261 mutex_unlock(&data->lock); 262 return ret; 263 } 264 265 static int rmi_mcamsr_input(struct sbrmi_data *data, struct apml_mcamsr_msg *msg, 266 u16 thread) 267 { 268 struct cpu_msr_indata input = {0}; 269 int val = 0, ret; 270 271 /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ 272 if (thread > 127) { 273 thread -= 128; 274 val = 1; 275 } 276 277 ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); 278 if (ret < 0) 279 return ret; 280 281 prepare_mca_msr_input_message(&input, thread, 282 msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK); 283 284 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 285 &input, MSR_WR_REG_LEN); 286 } 287 288 static int rmi_mcamsr_input_ext(struct sbrmi_data *data, struct apml_mcamsr_msg *msg, 289 u16 thread) 290 { 291 struct cpu_msr_indata_ext input = {0}; 292 293 prepare_mca_msr_input_message_ext(&input, thread, 294 msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK); 295 296 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 297 &input, MSR_WR_REG_LEN_EXT); 298 } 299 300 /* MCA MSR protocol */ 301 static int rmi_mca_msr_read(struct sbrmi_data *data, 302 struct apml_mcamsr_msg *msg) 303 { 304 struct cpu_msr_outdata output = {0}; 305 int ret; 306 int hw_status; 307 u16 thread; 308 309 mutex_lock(&data->lock); 310 /* cache the rev value to identify if protocol is supported or not */ 311 if (!data->rev) { 312 ret = sbrmi_get_rev(data); 313 if (ret < 0) 314 goto exit_unlock; 315 } 316 317 /* Extract thread from the input msg structure */ 318 thread = msg->mcamsr_in_out >> CPUID_MCA_THRD_INDEX; 319 320 switch (data->rev) { 321 case 0x10: 322 /* MCAMSR protocol for REV 0x10 is not supported*/ 323 ret = -EOPNOTSUPP; 324 goto exit_unlock; 325 case 0x20: 326 ret = rmi_mcamsr_input(data, msg, thread); 327 if (ret) 328 goto exit_unlock; 329 break; 330 case 0x21: 331 case 0x31: 332 ret = rmi_mcamsr_input_ext(data, msg, thread); 333 if (ret) 334 goto exit_unlock; 335 break; 336 default: 337 ret = -EOPNOTSUPP; 338 goto exit_unlock; 339 } 340 341 /* 342 * For RMI Rev 0x20, new h/w status bit is introduced. which is used 343 * by firmware to indicate completion of commands (0x71, 0x72, 0x73). 344 * wait for the status bit to be set by the hardware before 345 * reading the data out. 346 */ 347 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, 348 hw_status & HW_ALERT_MASK, 500, 2000000); 349 if (ret) 350 goto exit_unlock; 351 352 ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, 353 &output, MSR_RD_REG_LEN); 354 if (ret < 0) 355 goto exit_unlock; 356 357 ret = regmap_write(data->regmap, SBRMI_STATUS, 358 HW_ALERT_MASK); 359 if (ret < 0) 360 goto exit_unlock; 361 362 if (output.num_bytes != MSR_RD_REG_LEN - 1) { 363 ret = -EMSGSIZE; 364 goto exit_unlock; 365 } 366 if (output.status) { 367 ret = -EPROTOTYPE; 368 msg->fw_ret_code = output.status; 369 goto exit_unlock; 370 } 371 msg->mcamsr_in_out = output.value; 372 373 exit_unlock: 374 mutex_unlock(&data->lock); 375 return ret; 376 } 377 378 int rmi_mailbox_xfer(struct sbrmi_data *data, 379 struct apml_mbox_msg *msg) 380 { 381 unsigned int bytes, ec; 382 int i, ret; 383 int sw_status; 384 u8 byte; 385 386 mutex_lock(&data->lock); 387 388 msg->fw_ret_code = 0; 389 390 /* Indicate firmware a command is to be serviced */ 391 ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD); 392 if (ret < 0) 393 goto exit_unlock; 394 395 /* Write the command to SBRMI::InBndMsg_inst0 */ 396 ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd); 397 if (ret < 0) 398 goto exit_unlock; 399 400 /* 401 * For both read and write the initiator (BMC) writes 402 * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] 403 * SBRMI_x3C(MSB):SBRMI_x39(LSB) 404 */ 405 for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { 406 byte = (msg->mb_in_out >> i * 8) & 0xff; 407 ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte); 408 if (ret < 0) 409 goto exit_unlock; 410 } 411 412 /* 413 * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to 414 * perform the requested read or write command 415 */ 416 ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); 417 if (ret < 0) 418 goto exit_unlock; 419 420 /* 421 * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate 422 * an ALERT (if enabled) to initiator (BMC) to indicate completion 423 * of the requested command 424 */ 425 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, sw_status, 426 sw_status & SW_ALERT_MASK, 500, 2000000); 427 if (ret) 428 goto exit_unlock; 429 430 ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG7, &ec); 431 if (ret || ec) 432 goto exit_clear_alert; 433 434 /* Clear the input value before updating the output data */ 435 msg->mb_in_out = 0; 436 437 /* 438 * For a read operation, the initiator (BMC) reads the firmware 439 * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] 440 * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. 441 */ 442 for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { 443 ret = regmap_read(data->regmap, 444 SBRMI_OUTBNDMSG1 + i, &bytes); 445 if (ret < 0) 446 break; 447 msg->mb_in_out |= bytes << i * 8; 448 } 449 450 exit_clear_alert: 451 /* 452 * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the 453 * ALERT to initiator 454 */ 455 ret = regmap_write(data->regmap, SBRMI_STATUS, 456 sw_status | SW_ALERT_MASK); 457 if (ec) { 458 ret = -EPROTOTYPE; 459 msg->fw_ret_code = ec; 460 } 461 exit_unlock: 462 mutex_unlock(&data->lock); 463 return ret; 464 } 465 466 static int apml_rmi_reg_xfer(struct sbrmi_data *data, 467 struct apml_reg_xfer_msg __user *arg) 468 { 469 struct apml_reg_xfer_msg msg = { 0 }; 470 unsigned int data_read; 471 int ret; 472 473 /* Copy the structure from user */ 474 if (copy_from_user(&msg, arg, sizeof(struct apml_reg_xfer_msg))) 475 return -EFAULT; 476 477 mutex_lock(&data->lock); 478 if (msg.rflag) { 479 ret = regmap_read(data->regmap, msg.reg_addr, &data_read); 480 if (!ret) 481 msg.data_in_out = data_read; 482 } else { 483 ret = regmap_write(data->regmap, msg.reg_addr, msg.data_in_out); 484 } 485 486 mutex_unlock(&data->lock); 487 488 if (msg.rflag && !ret) 489 if (copy_to_user(arg, &msg, sizeof(struct apml_reg_xfer_msg))) 490 return -EFAULT; 491 return ret; 492 } 493 494 static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __user *arg) 495 { 496 struct apml_mbox_msg msg = { 0 }; 497 int ret; 498 499 /* Copy the structure from user */ 500 if (copy_from_user(&msg, arg, sizeof(struct apml_mbox_msg))) 501 return -EFAULT; 502 503 /* Mailbox protocol */ 504 ret = rmi_mailbox_xfer(data, &msg); 505 if (ret && ret != -EPROTOTYPE) 506 return ret; 507 508 if (copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg))) 509 return -EFAULT; 510 return ret; 511 } 512 513 static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg) 514 { 515 struct apml_cpuid_msg msg = { 0 }; 516 int ret; 517 518 /* Copy the structure from user */ 519 if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg))) 520 return -EFAULT; 521 522 /* CPUID Protocol */ 523 ret = rmi_cpuid_read(data, &msg); 524 if (ret && ret != -EPROTOTYPE) 525 return ret; 526 527 if (copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg))) 528 return -EFAULT; 529 return ret; 530 } 531 532 static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg) 533 { 534 struct apml_mcamsr_msg msg = { 0 }; 535 int ret; 536 537 /* Copy the structure from user */ 538 if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg))) 539 return -EFAULT; 540 541 /* MCAMSR Protocol */ 542 ret = rmi_mca_msr_read(data, &msg); 543 if (ret && ret != -EPROTOTYPE) 544 return ret; 545 546 if (copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg))) 547 return -EFAULT; 548 return ret; 549 } 550 551 static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 552 { 553 void __user *argp = (void __user *)arg; 554 struct sbrmi_data *data; 555 556 data = container_of(fp->private_data, struct sbrmi_data, sbrmi_misc_dev); 557 switch (cmd) { 558 case SBRMI_IOCTL_MBOX_CMD: 559 return apml_mailbox_xfer(data, argp); 560 case SBRMI_IOCTL_CPUID_CMD: 561 return apml_cpuid_xfer(data, argp); 562 case SBRMI_IOCTL_MCAMSR_CMD: 563 return apml_mcamsr_xfer(data, argp); 564 case SBRMI_IOCTL_REG_XFER_CMD: 565 return apml_rmi_reg_xfer(data, argp); 566 default: 567 return -ENOTTY; 568 } 569 } 570 571 static const struct file_operations sbrmi_fops = { 572 .owner = THIS_MODULE, 573 .unlocked_ioctl = sbrmi_ioctl, 574 .compat_ioctl = compat_ptr_ioctl, 575 }; 576 577 int create_misc_rmi_device(struct sbrmi_data *data, 578 struct device *dev) 579 { 580 data->sbrmi_misc_dev.name = devm_kasprintf(dev, 581 GFP_KERNEL, 582 "sbrmi-%x", 583 data->dev_static_addr); 584 data->sbrmi_misc_dev.minor = MISC_DYNAMIC_MINOR; 585 data->sbrmi_misc_dev.fops = &sbrmi_fops; 586 data->sbrmi_misc_dev.parent = dev; 587 data->sbrmi_misc_dev.nodename = devm_kasprintf(dev, 588 GFP_KERNEL, 589 "sbrmi-%x", 590 data->dev_static_addr); 591 data->sbrmi_misc_dev.mode = 0600; 592 593 return misc_register(&data->sbrmi_misc_dev); 594 } 595