1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Loongson-2K Board Management Controller (BMC) Core Driver. 4 * 5 * Copyright (C) 2024-2025 Loongson Technology Corporation Limited. 6 * 7 * Authors: 8 * Chong Qiao <qiaochong@loongson.cn> 9 * Binbin Zhou <zhoubinbin@loongson.cn> 10 */ 11 12 #include <linux/aperture.h> 13 #include <linux/bitfield.h> 14 #include <linux/delay.h> 15 #include <linux/errno.h> 16 #include <linux/init.h> 17 #include <linux/iopoll.h> 18 #include <linux/kbd_kern.h> 19 #include <linux/kernel.h> 20 #include <linux/mfd/core.h> 21 #include <linux/module.h> 22 #include <linux/pci.h> 23 #include <linux/pci_ids.h> 24 #include <linux/platform_data/simplefb.h> 25 #include <linux/platform_device.h> 26 #include <linux/stop_machine.h> 27 #include <linux/vt_kern.h> 28 29 /* LS2K BMC resources */ 30 #define LS2K_DISPLAY_RES_START (SZ_16M + SZ_2M) 31 #define LS2K_IPMI_RES_SIZE 0x1C 32 #define LS2K_IPMI0_RES_START (SZ_16M + 0xF00000) 33 #define LS2K_IPMI1_RES_START (LS2K_IPMI0_RES_START + LS2K_IPMI_RES_SIZE) 34 #define LS2K_IPMI2_RES_START (LS2K_IPMI1_RES_START + LS2K_IPMI_RES_SIZE) 35 #define LS2K_IPMI3_RES_START (LS2K_IPMI2_RES_START + LS2K_IPMI_RES_SIZE) 36 #define LS2K_IPMI4_RES_START (LS2K_IPMI3_RES_START + LS2K_IPMI_RES_SIZE) 37 38 #define LS7A_PCI_CFG_SIZE 0x100 39 40 /* LS7A bridge registers */ 41 #define LS7A_PCIE_PORT_CTL0 0x0 42 #define LS7A_PCIE_PORT_STS1 0xC 43 #define LS7A_GEN2_CTL 0x80C 44 #define LS7A_SYMBOL_TIMER 0x71C 45 46 /* Bits of LS7A_PCIE_PORT_CTL0 */ 47 #define LS2K_BMC_PCIE_LTSSM_ENABLE BIT(3) 48 49 /* Bits of LS7A_PCIE_PORT_STS1 */ 50 #define LS2K_BMC_PCIE_LTSSM_STS GENMASK(5, 0) 51 #define LS2K_BMC_PCIE_CONNECTED 0x11 52 53 #define LS2K_BMC_PCIE_DELAY_US 1000 54 #define LS2K_BMC_PCIE_TIMEOUT_US 1000000 55 56 /* Bits of LS7A_GEN2_CTL */ 57 #define LS7A_GEN2_SPEED_CHANG BIT(17) 58 #define LS7A_CONF_PHY_TX BIT(18) 59 60 /* Bits of LS7A_SYMBOL_TIMER */ 61 #define LS7A_MASK_LEN_MATCH BIT(26) 62 63 /* Interval between interruptions */ 64 #define LS2K_BMC_INT_INTERVAL (60 * HZ) 65 66 /* Maximum time to wait for U-Boot and DDR to be ready with ms. */ 67 #define LS2K_BMC_RESET_WAIT_TIME 10000 68 69 /* It's an experience value */ 70 #define LS7A_BAR0_CHECK_MAX_TIMES 2000 71 72 #define PCI_REG_STRIDE 0x4 73 74 #define LS2K_BMC_RESET_GPIO 14 75 #define LOONGSON_GPIO_REG_BASE 0x1FE00500 76 #define LOONGSON_GPIO_REG_SIZE 0x18 77 #define LOONGSON_GPIO_OEN 0x0 78 #define LOONGSON_GPIO_FUNC 0x4 79 #define LOONGSON_GPIO_INTPOL 0x10 80 #define LOONGSON_GPIO_INTEN 0x14 81 82 #define LOONGSON_IO_INT_BASE 16 83 #define LS2K_BMC_RESET_GPIO_INT_VEC (LS2K_BMC_RESET_GPIO % 8) 84 #define LS2K_BMC_RESET_GPIO_GSI (LOONGSON_IO_INT_BASE + LS2K_BMC_RESET_GPIO_INT_VEC) 85 86 enum { 87 LS2K_BMC_DISPLAY, 88 LS2K_BMC_IPMI0, 89 LS2K_BMC_IPMI1, 90 LS2K_BMC_IPMI2, 91 LS2K_BMC_IPMI3, 92 LS2K_BMC_IPMI4, 93 }; 94 95 static struct resource ls2k_display_resources[] = { 96 DEFINE_RES_MEM_NAMED(LS2K_DISPLAY_RES_START, SZ_4M, "simpledrm-res"), 97 }; 98 99 static struct resource ls2k_ipmi0_resources[] = { 100 DEFINE_RES_MEM_NAMED(LS2K_IPMI0_RES_START, LS2K_IPMI_RES_SIZE, "ipmi0-res"), 101 }; 102 103 static struct resource ls2k_ipmi1_resources[] = { 104 DEFINE_RES_MEM_NAMED(LS2K_IPMI1_RES_START, LS2K_IPMI_RES_SIZE, "ipmi1-res"), 105 }; 106 107 static struct resource ls2k_ipmi2_resources[] = { 108 DEFINE_RES_MEM_NAMED(LS2K_IPMI2_RES_START, LS2K_IPMI_RES_SIZE, "ipmi2-res"), 109 }; 110 111 static struct resource ls2k_ipmi3_resources[] = { 112 DEFINE_RES_MEM_NAMED(LS2K_IPMI3_RES_START, LS2K_IPMI_RES_SIZE, "ipmi3-res"), 113 }; 114 115 static struct resource ls2k_ipmi4_resources[] = { 116 DEFINE_RES_MEM_NAMED(LS2K_IPMI4_RES_START, LS2K_IPMI_RES_SIZE, "ipmi4-res"), 117 }; 118 119 static struct mfd_cell ls2k_bmc_cells[] = { 120 [LS2K_BMC_DISPLAY] = { 121 .name = "simple-framebuffer", 122 .num_resources = ARRAY_SIZE(ls2k_display_resources), 123 .resources = ls2k_display_resources 124 }, 125 [LS2K_BMC_IPMI0] = { 126 .name = "ls2k-ipmi-si", 127 .num_resources = ARRAY_SIZE(ls2k_ipmi0_resources), 128 .resources = ls2k_ipmi0_resources 129 }, 130 [LS2K_BMC_IPMI1] = { 131 .name = "ls2k-ipmi-si", 132 .num_resources = ARRAY_SIZE(ls2k_ipmi1_resources), 133 .resources = ls2k_ipmi1_resources 134 }, 135 [LS2K_BMC_IPMI2] = { 136 .name = "ls2k-ipmi-si", 137 .num_resources = ARRAY_SIZE(ls2k_ipmi2_resources), 138 .resources = ls2k_ipmi2_resources 139 }, 140 [LS2K_BMC_IPMI3] = { 141 .name = "ls2k-ipmi-si", 142 .num_resources = ARRAY_SIZE(ls2k_ipmi3_resources), 143 .resources = ls2k_ipmi3_resources 144 }, 145 [LS2K_BMC_IPMI4] = { 146 .name = "ls2k-ipmi-si", 147 .num_resources = ARRAY_SIZE(ls2k_ipmi4_resources), 148 .resources = ls2k_ipmi4_resources 149 }, 150 }; 151 152 /* Index of the BMC PCI configuration space to be restored at BMC reset. */ 153 struct ls2k_bmc_pci_data { 154 u32 pci_command; 155 u32 base_address0; 156 u32 interrupt_line; 157 }; 158 159 /* Index of the parent PCI configuration space to be restored at BMC reset. */ 160 struct ls2k_bmc_bridge_pci_data { 161 u32 pci_command; 162 u32 base_address[6]; 163 u32 rom_addreess; 164 u32 interrupt_line; 165 u32 msi_hi; 166 u32 msi_lo; 167 u32 devctl; 168 u32 linkcap; 169 u32 linkctl_sts; 170 u32 symbol_timer; 171 u32 gen2_ctrl; 172 }; 173 174 struct ls2k_bmc_ddata { 175 struct device *dev; 176 struct work_struct bmc_reset_work; 177 struct ls2k_bmc_pci_data bmc_pci_data; 178 struct ls2k_bmc_bridge_pci_data bridge_pci_data; 179 }; 180 181 static bool ls2k_bmc_bar0_addr_is_set(struct pci_dev *pdev) 182 { 183 u32 addr; 184 185 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &addr); 186 187 return addr & PCI_BASE_ADDRESS_MEM_MASK ? true : false; 188 } 189 190 static bool ls2k_bmc_pcie_is_connected(struct pci_dev *parent, struct ls2k_bmc_ddata *ddata) 191 { 192 void __iomem *base; 193 int val, ret; 194 195 base = pci_iomap(parent, 0, LS7A_PCI_CFG_SIZE); 196 if (!base) 197 return false; 198 199 val = readl(base + LS7A_PCIE_PORT_CTL0); 200 writel(val | LS2K_BMC_PCIE_LTSSM_ENABLE, base + LS7A_PCIE_PORT_CTL0); 201 202 ret = readl_poll_timeout_atomic(base + LS7A_PCIE_PORT_STS1, val, 203 (val & LS2K_BMC_PCIE_LTSSM_STS) == LS2K_BMC_PCIE_CONNECTED, 204 LS2K_BMC_PCIE_DELAY_US, LS2K_BMC_PCIE_TIMEOUT_US); 205 if (ret) { 206 pci_iounmap(parent, base); 207 dev_err(ddata->dev, "PCI-E training failed status=0x%x\n", val); 208 return false; 209 } 210 211 pci_iounmap(parent, base); 212 return true; 213 } 214 215 static void ls2k_bmc_restore_bridge_pci_data(struct pci_dev *parent, struct ls2k_bmc_ddata *ddata) 216 { 217 int base, i = 0; 218 219 pci_write_config_dword(parent, PCI_COMMAND, ddata->bridge_pci_data.pci_command); 220 221 for (base = PCI_BASE_ADDRESS_0; base <= PCI_BASE_ADDRESS_5; base += PCI_REG_STRIDE, i++) 222 pci_write_config_dword(parent, base, ddata->bridge_pci_data.base_address[i]); 223 224 pci_write_config_dword(parent, PCI_ROM_ADDRESS, ddata->bridge_pci_data.rom_addreess); 225 pci_write_config_dword(parent, PCI_INTERRUPT_LINE, ddata->bridge_pci_data.interrupt_line); 226 227 pci_write_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_LO, 228 ddata->bridge_pci_data.msi_lo); 229 pci_write_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_HI, 230 ddata->bridge_pci_data.msi_hi); 231 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_DEVCTL, 232 ddata->bridge_pci_data.devctl); 233 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, 234 ddata->bridge_pci_data.linkcap); 235 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, 236 ddata->bridge_pci_data.linkctl_sts); 237 238 pci_write_config_dword(parent, LS7A_GEN2_CTL, ddata->bridge_pci_data.gen2_ctrl); 239 pci_write_config_dword(parent, LS7A_SYMBOL_TIMER, ddata->bridge_pci_data.symbol_timer); 240 } 241 242 static int ls2k_bmc_recover_pci_data(void *data) 243 { 244 struct ls2k_bmc_ddata *ddata = data; 245 struct pci_dev *pdev = to_pci_dev(ddata->dev); 246 struct pci_dev *parent = pdev->bus->self; 247 u32 i; 248 249 /* 250 * Clear the bus, io and mem resources of the PCI-E bridge to zero, so that 251 * the processor can not access the LS2K PCI-E port, to avoid crashing due to 252 * the lack of return signal from accessing the LS2K PCI-E port. 253 */ 254 pci_write_config_dword(parent, PCI_BASE_ADDRESS_2, 0); 255 pci_write_config_dword(parent, PCI_BASE_ADDRESS_3, 0); 256 pci_write_config_dword(parent, PCI_BASE_ADDRESS_4, 0); 257 258 /* 259 * When the LS2K BMC is reset, the LS7A PCI-E port is also reset, and its PCI 260 * BAR0 register is cleared. Due to the time gap between the GPIO interrupt 261 * generation and the LS2K BMC reset, the LS7A PCI BAR0 register is read to 262 * determine whether the reset has begun. 263 */ 264 for (i = LS7A_BAR0_CHECK_MAX_TIMES; i > 0 ; i--) { 265 if (!ls2k_bmc_bar0_addr_is_set(parent)) 266 break; 267 mdelay(1); 268 }; 269 270 if (i == 0) 271 return false; 272 273 ls2k_bmc_restore_bridge_pci_data(parent, ddata); 274 275 /* Check if PCI-E is connected */ 276 if (!ls2k_bmc_pcie_is_connected(parent, ddata)) 277 return false; 278 279 /* Waiting for U-Boot and DDR ready */ 280 mdelay(LS2K_BMC_RESET_WAIT_TIME); 281 if (!ls2k_bmc_bar0_addr_is_set(parent)) 282 return false; 283 284 /* Restore LS2K BMC PCI-E config data */ 285 pci_write_config_dword(pdev, PCI_COMMAND, ddata->bmc_pci_data.pci_command); 286 pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ddata->bmc_pci_data.base_address0); 287 pci_write_config_dword(pdev, PCI_INTERRUPT_LINE, ddata->bmc_pci_data.interrupt_line); 288 289 return 0; 290 } 291 292 static void ls2k_bmc_events_fn(struct work_struct *work) 293 { 294 struct ls2k_bmc_ddata *ddata = container_of(work, struct ls2k_bmc_ddata, bmc_reset_work); 295 296 /* 297 * The PCI-E is lost when the BMC resets, at which point access to the PCI-E 298 * from other CPUs is suspended to prevent a crash. 299 */ 300 stop_machine(ls2k_bmc_recover_pci_data, ddata, NULL); 301 302 if (IS_ENABLED(CONFIG_VT)) { 303 /* Re-push the display due to previous PCI-E loss. */ 304 set_console(vt_move_to_console(MAX_NR_CONSOLES - 1, 1)); 305 } 306 } 307 308 static irqreturn_t ls2k_bmc_interrupt(int irq, void *arg) 309 { 310 struct ls2k_bmc_ddata *ddata = arg; 311 static unsigned long last_jiffies; 312 313 if (system_state != SYSTEM_RUNNING) 314 return IRQ_HANDLED; 315 316 /* Skip interrupt in LS2K_BMC_INT_INTERVAL */ 317 if (time_after(jiffies, last_jiffies + LS2K_BMC_INT_INTERVAL)) { 318 schedule_work(&ddata->bmc_reset_work); 319 last_jiffies = jiffies; 320 } 321 322 return IRQ_HANDLED; 323 } 324 325 /* 326 * Saves the BMC parent device (LS7A) and its own PCI configuration space registers 327 * that need to be restored after BMC reset. 328 */ 329 static void ls2k_bmc_save_pci_data(struct pci_dev *pdev, struct ls2k_bmc_ddata *ddata) 330 { 331 struct pci_dev *parent = pdev->bus->self; 332 int base, i = 0; 333 334 pci_read_config_dword(parent, PCI_COMMAND, &ddata->bridge_pci_data.pci_command); 335 336 for (base = PCI_BASE_ADDRESS_0; base <= PCI_BASE_ADDRESS_5; base += PCI_REG_STRIDE, i++) 337 pci_read_config_dword(parent, base, &ddata->bridge_pci_data.base_address[i]); 338 339 pci_read_config_dword(parent, PCI_ROM_ADDRESS, &ddata->bridge_pci_data.rom_addreess); 340 pci_read_config_dword(parent, PCI_INTERRUPT_LINE, &ddata->bridge_pci_data.interrupt_line); 341 342 pci_read_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_LO, 343 &ddata->bridge_pci_data.msi_lo); 344 pci_read_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_HI, 345 &ddata->bridge_pci_data.msi_hi); 346 347 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_DEVCTL, 348 &ddata->bridge_pci_data.devctl); 349 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, 350 &ddata->bridge_pci_data.linkcap); 351 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, 352 &ddata->bridge_pci_data.linkctl_sts); 353 354 pci_read_config_dword(parent, LS7A_GEN2_CTL, &ddata->bridge_pci_data.gen2_ctrl); 355 ddata->bridge_pci_data.gen2_ctrl |= FIELD_PREP(LS7A_GEN2_SPEED_CHANG, 0x1) | 356 FIELD_PREP(LS7A_CONF_PHY_TX, 0x0); 357 358 pci_read_config_dword(parent, LS7A_SYMBOL_TIMER, &ddata->bridge_pci_data.symbol_timer); 359 ddata->bridge_pci_data.symbol_timer |= LS7A_MASK_LEN_MATCH; 360 361 pci_read_config_dword(pdev, PCI_COMMAND, &ddata->bmc_pci_data.pci_command); 362 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &ddata->bmc_pci_data.base_address0); 363 pci_read_config_dword(pdev, PCI_INTERRUPT_LINE, &ddata->bmc_pci_data.interrupt_line); 364 } 365 366 static int ls2k_bmc_init(struct ls2k_bmc_ddata *ddata) 367 { 368 struct pci_dev *pdev = to_pci_dev(ddata->dev); 369 void __iomem *gpio_base; 370 int gpio_irq, ret, val; 371 372 ls2k_bmc_save_pci_data(pdev, ddata); 373 374 INIT_WORK(&ddata->bmc_reset_work, ls2k_bmc_events_fn); 375 376 ret = devm_request_irq(&pdev->dev, pdev->irq, ls2k_bmc_interrupt, 377 IRQF_SHARED | IRQF_TRIGGER_FALLING, "ls2kbmc pcie", ddata); 378 if (ret) { 379 dev_err(ddata->dev, "Failed to request LS2KBMC PCI-E IRQ %d.\n", pdev->irq); 380 return ret; 381 } 382 383 gpio_base = ioremap(LOONGSON_GPIO_REG_BASE, LOONGSON_GPIO_REG_SIZE); 384 if (!gpio_base) 385 return -ENOMEM; 386 387 /* Disable GPIO output */ 388 val = readl(gpio_base + LOONGSON_GPIO_OEN); 389 writel(val | BIT(LS2K_BMC_RESET_GPIO), gpio_base + LOONGSON_GPIO_OEN); 390 391 /* Enable GPIO functionality */ 392 val = readl(gpio_base + LOONGSON_GPIO_FUNC); 393 writel(val & ~BIT(LS2K_BMC_RESET_GPIO), gpio_base + LOONGSON_GPIO_FUNC); 394 395 /* Set GPIO interrupts to low-level active */ 396 val = readl(gpio_base + LOONGSON_GPIO_INTPOL); 397 writel(val & ~BIT(LS2K_BMC_RESET_GPIO), gpio_base + LOONGSON_GPIO_INTPOL); 398 399 /* Enable GPIO interrupts */ 400 val = readl(gpio_base + LOONGSON_GPIO_INTEN); 401 writel(val | BIT(LS2K_BMC_RESET_GPIO), gpio_base + LOONGSON_GPIO_INTEN); 402 403 iounmap(gpio_base); 404 405 /* 406 * Since gpio_chip->to_irq is not implemented in the Loongson-3 GPIO driver, 407 * acpi_register_gsi() is used to obtain the GPIO IRQ. The GPIO interrupt is a 408 * watchdog interrupt that is triggered when the BMC resets. 409 */ 410 gpio_irq = acpi_register_gsi(NULL, LS2K_BMC_RESET_GPIO_GSI, ACPI_EDGE_SENSITIVE, 411 ACPI_ACTIVE_LOW); 412 if (gpio_irq < 0) 413 return gpio_irq; 414 415 ret = devm_request_irq(ddata->dev, gpio_irq, ls2k_bmc_interrupt, 416 IRQF_SHARED | IRQF_TRIGGER_FALLING, "ls2kbmc gpio", ddata); 417 if (ret) 418 dev_err(ddata->dev, "Failed to request LS2KBMC GPIO IRQ %d.\n", gpio_irq); 419 420 acpi_unregister_gsi(LS2K_BMC_RESET_GPIO_GSI); 421 return ret; 422 } 423 424 /* 425 * Currently the Loongson-2K BMC hardware does not have an I2C interface to adapt to the 426 * resolution. We set the resolution by presetting "video=1280x1024-16@2M" to the BMC memory. 427 */ 428 static int ls2k_bmc_parse_mode(struct pci_dev *pdev, struct simplefb_platform_data *pd) 429 { 430 char *mode; 431 int depth, ret; 432 433 /* The last 16M of PCI BAR0 is used to store the resolution string. */ 434 mode = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0) + SZ_16M, SZ_16M); 435 if (!mode) 436 return -ENOMEM; 437 438 /* The resolution field starts with the flag "video=". */ 439 if (!strncmp(mode, "video=", 6)) 440 mode = mode + 6; 441 442 ret = kstrtoint(strsep(&mode, "x"), 10, &pd->width); 443 if (ret) 444 return ret; 445 446 ret = kstrtoint(strsep(&mode, "-"), 10, &pd->height); 447 if (ret) 448 return ret; 449 450 ret = kstrtoint(strsep(&mode, "@"), 10, &depth); 451 if (ret) 452 return ret; 453 454 pd->stride = pd->width * depth / 8; 455 pd->format = depth == 32 ? "a8r8g8b8" : "r5g6b5"; 456 457 return 0; 458 } 459 460 static int ls2k_bmc_probe(struct pci_dev *dev, const struct pci_device_id *id) 461 { 462 struct simplefb_platform_data pd; 463 struct ls2k_bmc_ddata *ddata; 464 resource_size_t base; 465 int ret; 466 467 ret = pci_enable_device(dev); 468 if (ret) 469 return ret; 470 471 ddata = devm_kzalloc(&dev->dev, sizeof(*ddata), GFP_KERNEL); 472 if (IS_ERR(ddata)) { 473 ret = -ENOMEM; 474 goto disable_pci; 475 } 476 477 ddata->dev = &dev->dev; 478 479 ret = ls2k_bmc_init(ddata); 480 if (ret) 481 goto disable_pci; 482 483 ret = ls2k_bmc_parse_mode(dev, &pd); 484 if (ret) 485 goto disable_pci; 486 487 ls2k_bmc_cells[LS2K_BMC_DISPLAY].platform_data = &pd; 488 ls2k_bmc_cells[LS2K_BMC_DISPLAY].pdata_size = sizeof(pd); 489 base = dev->resource[0].start + LS2K_DISPLAY_RES_START; 490 491 /* Remove conflicting efifb device */ 492 ret = aperture_remove_conflicting_devices(base, SZ_4M, "simple-framebuffer"); 493 if (ret) { 494 dev_err(&dev->dev, "Failed to removed firmware framebuffers: %d\n", ret); 495 goto disable_pci; 496 } 497 498 return devm_mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, 499 ls2k_bmc_cells, ARRAY_SIZE(ls2k_bmc_cells), 500 &dev->resource[0], 0, NULL); 501 502 disable_pci: 503 pci_disable_device(dev); 504 return ret; 505 } 506 507 static void ls2k_bmc_remove(struct pci_dev *dev) 508 { 509 pci_disable_device(dev); 510 } 511 512 static struct pci_device_id ls2k_bmc_devices[] = { 513 { PCI_DEVICE(PCI_VENDOR_ID_LOONGSON, 0x1a05) }, 514 { } 515 }; 516 MODULE_DEVICE_TABLE(pci, ls2k_bmc_devices); 517 518 static struct pci_driver ls2k_bmc_driver = { 519 .name = "ls2k-bmc", 520 .id_table = ls2k_bmc_devices, 521 .probe = ls2k_bmc_probe, 522 .remove = ls2k_bmc_remove, 523 }; 524 module_pci_driver(ls2k_bmc_driver); 525 526 MODULE_DESCRIPTION("Loongson-2K Board Management Controller (BMC) Core driver"); 527 MODULE_AUTHOR("Loongson Technology Corporation Limited"); 528 MODULE_LICENSE("GPL"); 529