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 56 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 ret = rmi_cpuid_input_ext(data, msg, thread); 218 if (ret) 219 goto exit_unlock; 220 break; 221 default: 222 ret = -EOPNOTSUPP; 223 goto exit_unlock; 224 } 225 226 /* 227 * For RMI Rev 0x20, new h/w status bit is introduced. which is used 228 * by firmware to indicate completion of commands (0x71, 0x72, 0x73). 229 * wait for the status bit to be set by the hardware before 230 * reading the data out. 231 */ 232 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, 233 hw_status & HW_ALERT_MASK, 500, 2000000); 234 if (ret) 235 goto exit_unlock; 236 237 ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, 238 &output, CPUID_RD_REG_LEN); 239 if (ret < 0) 240 goto exit_unlock; 241 242 ret = regmap_write(data->regmap, SBRMI_STATUS, 243 HW_ALERT_MASK); 244 if (ret < 0) 245 goto exit_unlock; 246 247 if (output.num_bytes != CPUID_RD_REG_LEN - 1) { 248 ret = -EMSGSIZE; 249 goto exit_unlock; 250 } 251 if (output.status) { 252 ret = -EPROTOTYPE; 253 msg->fw_ret_code = output.status; 254 goto exit_unlock; 255 } 256 msg->cpu_in_out = output.value; 257 exit_unlock: 258 if (ret < 0) 259 msg->cpu_in_out = 0; 260 mutex_unlock(&data->lock); 261 return ret; 262 } 263 264 static int rmi_mcamsr_input(struct sbrmi_data *data, struct apml_mcamsr_msg *msg, 265 u16 thread) 266 { 267 struct cpu_msr_indata input = {0}; 268 int val = 0, ret; 269 270 /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ 271 if (thread > 127) { 272 thread -= 128; 273 val = 1; 274 } 275 276 ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); 277 if (ret < 0) 278 return ret; 279 280 prepare_mca_msr_input_message(&input, thread, 281 msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK); 282 283 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 284 &input, MSR_WR_REG_LEN); 285 } 286 287 static int rmi_mcamsr_input_ext(struct sbrmi_data *data, struct apml_mcamsr_msg *msg, 288 u16 thread) 289 { 290 struct cpu_msr_indata_ext input = {0}; 291 292 prepare_mca_msr_input_message_ext(&input, thread, 293 msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK); 294 295 return regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 296 &input, MSR_WR_REG_LEN_EXT); 297 } 298 299 /* MCA MSR protocol */ 300 static int rmi_mca_msr_read(struct sbrmi_data *data, 301 struct apml_mcamsr_msg *msg) 302 { 303 struct cpu_msr_outdata output = {0}; 304 int ret; 305 int hw_status; 306 u16 thread; 307 308 mutex_lock(&data->lock); 309 /* cache the rev value to identify if protocol is supported or not */ 310 if (!data->rev) { 311 ret = sbrmi_get_rev(data); 312 if (ret < 0) 313 goto exit_unlock; 314 } 315 316 /* Extract thread from the input msg structure */ 317 thread = msg->mcamsr_in_out >> CPUID_MCA_THRD_INDEX; 318 319 switch (data->rev) { 320 case 0x10: 321 /* MCAMSR protocol for REV 0x10 is not supported*/ 322 ret = -EOPNOTSUPP; 323 goto exit_unlock; 324 case 0x20: 325 ret = rmi_mcamsr_input(data, msg, thread); 326 if (ret) 327 goto exit_unlock; 328 break; 329 case 0x21: 330 ret = rmi_mcamsr_input_ext(data, msg, thread); 331 if (ret) 332 goto exit_unlock; 333 break; 334 default: 335 ret = -EOPNOTSUPP; 336 goto exit_unlock; 337 } 338 339 /* 340 * For RMI Rev 0x20, new h/w status bit is introduced. which is used 341 * by firmware to indicate completion of commands (0x71, 0x72, 0x73). 342 * wait for the status bit to be set by the hardware before 343 * reading the data out. 344 */ 345 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, 346 hw_status & HW_ALERT_MASK, 500, 2000000); 347 if (ret) 348 goto exit_unlock; 349 350 ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, 351 &output, MSR_RD_REG_LEN); 352 if (ret < 0) 353 goto exit_unlock; 354 355 ret = regmap_write(data->regmap, SBRMI_STATUS, 356 HW_ALERT_MASK); 357 if (ret < 0) 358 goto exit_unlock; 359 360 if (output.num_bytes != MSR_RD_REG_LEN - 1) { 361 ret = -EMSGSIZE; 362 goto exit_unlock; 363 } 364 if (output.status) { 365 ret = -EPROTOTYPE; 366 msg->fw_ret_code = output.status; 367 goto exit_unlock; 368 } 369 msg->mcamsr_in_out = output.value; 370 371 exit_unlock: 372 mutex_unlock(&data->lock); 373 return ret; 374 } 375 376 int rmi_mailbox_xfer(struct sbrmi_data *data, 377 struct apml_mbox_msg *msg) 378 { 379 unsigned int bytes, ec; 380 int i, ret; 381 int sw_status; 382 u8 byte; 383 384 mutex_lock(&data->lock); 385 386 msg->fw_ret_code = 0; 387 388 /* Indicate firmware a command is to be serviced */ 389 ret = regmap_write(data->regmap, SBRMI_INBNDMSG7, START_CMD); 390 if (ret < 0) 391 goto exit_unlock; 392 393 /* Write the command to SBRMI::InBndMsg_inst0 */ 394 ret = regmap_write(data->regmap, SBRMI_INBNDMSG0, msg->cmd); 395 if (ret < 0) 396 goto exit_unlock; 397 398 /* 399 * For both read and write the initiator (BMC) writes 400 * Command Data In[31:0] to SBRMI::InBndMsg_inst[4:1] 401 * SBRMI_x3C(MSB):SBRMI_x39(LSB) 402 */ 403 for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { 404 byte = (msg->mb_in_out >> i * 8) & 0xff; 405 ret = regmap_write(data->regmap, SBRMI_INBNDMSG1 + i, byte); 406 if (ret < 0) 407 goto exit_unlock; 408 } 409 410 /* 411 * Write 0x01 to SBRMI::SoftwareInterrupt to notify firmware to 412 * perform the requested read or write command 413 */ 414 ret = regmap_write(data->regmap, SBRMI_SW_INTERRUPT, TRIGGER_MAILBOX); 415 if (ret < 0) 416 goto exit_unlock; 417 418 /* 419 * Firmware will write SBRMI::Status[SwAlertSts]=1 to generate 420 * an ALERT (if enabled) to initiator (BMC) to indicate completion 421 * of the requested command 422 */ 423 ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, sw_status, 424 sw_status & SW_ALERT_MASK, 500, 2000000); 425 if (ret) 426 goto exit_unlock; 427 428 ret = regmap_read(data->regmap, SBRMI_OUTBNDMSG7, &ec); 429 if (ret || ec) 430 goto exit_clear_alert; 431 432 /* Clear the input value before updating the output data */ 433 msg->mb_in_out = 0; 434 435 /* 436 * For a read operation, the initiator (BMC) reads the firmware 437 * response Command Data Out[31:0] from SBRMI::OutBndMsg_inst[4:1] 438 * {SBRMI_x34(MSB):SBRMI_x31(LSB)}. 439 */ 440 for (i = 0; i < AMD_SBI_MB_DATA_SIZE; i++) { 441 ret = regmap_read(data->regmap, 442 SBRMI_OUTBNDMSG1 + i, &bytes); 443 if (ret < 0) 444 break; 445 msg->mb_in_out |= bytes << i * 8; 446 } 447 448 exit_clear_alert: 449 /* 450 * BMC must write 1'b1 to SBRMI::Status[SwAlertSts] to clear the 451 * ALERT to initiator 452 */ 453 ret = regmap_write(data->regmap, SBRMI_STATUS, 454 sw_status | SW_ALERT_MASK); 455 if (ec) { 456 ret = -EPROTOTYPE; 457 msg->fw_ret_code = ec; 458 } 459 exit_unlock: 460 mutex_unlock(&data->lock); 461 return ret; 462 } 463 464 static int apml_rmi_reg_xfer(struct sbrmi_data *data, 465 struct apml_reg_xfer_msg __user *arg) 466 { 467 struct apml_reg_xfer_msg msg = { 0 }; 468 unsigned int data_read; 469 int ret; 470 471 /* Copy the structure from user */ 472 if (copy_from_user(&msg, arg, sizeof(struct apml_reg_xfer_msg))) 473 return -EFAULT; 474 475 mutex_lock(&data->lock); 476 if (msg.rflag) { 477 ret = regmap_read(data->regmap, msg.reg_addr, &data_read); 478 if (!ret) 479 msg.data_in_out = data_read; 480 } else { 481 ret = regmap_write(data->regmap, msg.reg_addr, msg.data_in_out); 482 } 483 484 mutex_unlock(&data->lock); 485 486 if (msg.rflag && !ret) 487 if (copy_to_user(arg, &msg, sizeof(struct apml_reg_xfer_msg))) 488 return -EFAULT; 489 return ret; 490 } 491 492 static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __user *arg) 493 { 494 struct apml_mbox_msg msg = { 0 }; 495 int ret; 496 497 /* Copy the structure from user */ 498 if (copy_from_user(&msg, arg, sizeof(struct apml_mbox_msg))) 499 return -EFAULT; 500 501 /* Mailbox protocol */ 502 ret = rmi_mailbox_xfer(data, &msg); 503 if (ret && ret != -EPROTOTYPE) 504 return ret; 505 506 if (copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg))) 507 return -EFAULT; 508 return ret; 509 } 510 511 static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg) 512 { 513 struct apml_cpuid_msg msg = { 0 }; 514 int ret; 515 516 /* Copy the structure from user */ 517 if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg))) 518 return -EFAULT; 519 520 /* CPUID Protocol */ 521 ret = rmi_cpuid_read(data, &msg); 522 if (ret && ret != -EPROTOTYPE) 523 return ret; 524 525 if (copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg))) 526 return -EFAULT; 527 return ret; 528 } 529 530 static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg) 531 { 532 struct apml_mcamsr_msg msg = { 0 }; 533 int ret; 534 535 /* Copy the structure from user */ 536 if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg))) 537 return -EFAULT; 538 539 /* MCAMSR Protocol */ 540 ret = rmi_mca_msr_read(data, &msg); 541 if (ret && ret != -EPROTOTYPE) 542 return ret; 543 544 if (copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg))) 545 return -EFAULT; 546 return ret; 547 } 548 549 static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 550 { 551 void __user *argp = (void __user *)arg; 552 struct sbrmi_data *data; 553 554 data = container_of(fp->private_data, struct sbrmi_data, sbrmi_misc_dev); 555 switch (cmd) { 556 case SBRMI_IOCTL_MBOX_CMD: 557 return apml_mailbox_xfer(data, argp); 558 case SBRMI_IOCTL_CPUID_CMD: 559 return apml_cpuid_xfer(data, argp); 560 case SBRMI_IOCTL_MCAMSR_CMD: 561 return apml_mcamsr_xfer(data, argp); 562 case SBRMI_IOCTL_REG_XFER_CMD: 563 return apml_rmi_reg_xfer(data, argp); 564 default: 565 return -ENOTTY; 566 } 567 } 568 569 static const struct file_operations sbrmi_fops = { 570 .owner = THIS_MODULE, 571 .unlocked_ioctl = sbrmi_ioctl, 572 .compat_ioctl = compat_ptr_ioctl, 573 }; 574 575 int create_misc_rmi_device(struct sbrmi_data *data, 576 struct device *dev) 577 { 578 data->sbrmi_misc_dev.name = devm_kasprintf(dev, 579 GFP_KERNEL, 580 "sbrmi-%x", 581 data->dev_static_addr); 582 data->sbrmi_misc_dev.minor = MISC_DYNAMIC_MINOR; 583 data->sbrmi_misc_dev.fops = &sbrmi_fops; 584 data->sbrmi_misc_dev.parent = dev; 585 data->sbrmi_misc_dev.nodename = devm_kasprintf(dev, 586 GFP_KERNEL, 587 "sbrmi-%x", 588 data->dev_static_addr); 589 data->sbrmi_misc_dev.mode = 0600; 590 591 return misc_register(&data->sbrmi_misc_dev); 592 } 593