Lines Matching +full:ls2k +full:- +full:gpio
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Loongson-2K Board Management Controller (BMC) Core Driver.
5 * Copyright (C) 2024-2025 Loongson Technology Corporation Limited.
29 /* LS2K BMC resources */
66 /* Maximum time to wait for U-Boot and DDR to be ready with ms. */
96 DEFINE_RES_MEM_NAMED(LS2K_DISPLAY_RES_START, SZ_4M, "simpledrm-res"),
100 DEFINE_RES_MEM_NAMED(LS2K_IPMI0_RES_START, LS2K_IPMI_RES_SIZE, "ipmi0-res"),
104 DEFINE_RES_MEM_NAMED(LS2K_IPMI1_RES_START, LS2K_IPMI_RES_SIZE, "ipmi1-res"),
108 DEFINE_RES_MEM_NAMED(LS2K_IPMI2_RES_START, LS2K_IPMI_RES_SIZE, "ipmi2-res"),
112 DEFINE_RES_MEM_NAMED(LS2K_IPMI3_RES_START, LS2K_IPMI_RES_SIZE, "ipmi3-res"),
116 DEFINE_RES_MEM_NAMED(LS2K_IPMI4_RES_START, LS2K_IPMI_RES_SIZE, "ipmi4-res"),
121 .name = "simple-framebuffer",
126 .name = "ls2k-ipmi-si",
131 .name = "ls2k-ipmi-si",
136 .name = "ls2k-ipmi-si",
141 .name = "ls2k-ipmi-si",
146 .name = "ls2k-ipmi-si",
207 dev_err(ddata->dev, "PCI-E training failed status=0x%x\n", val); in ls2k_bmc_pcie_is_connected()
219 pci_write_config_dword(parent, PCI_COMMAND, ddata->bridge_pci_data.pci_command); in ls2k_bmc_restore_bridge_pci_data()
222 pci_write_config_dword(parent, base, ddata->bridge_pci_data.base_address[i]); in ls2k_bmc_restore_bridge_pci_data()
224 pci_write_config_dword(parent, PCI_ROM_ADDRESS, ddata->bridge_pci_data.rom_addreess); in ls2k_bmc_restore_bridge_pci_data()
225 pci_write_config_dword(parent, PCI_INTERRUPT_LINE, ddata->bridge_pci_data.interrupt_line); in ls2k_bmc_restore_bridge_pci_data()
227 pci_write_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_LO, in ls2k_bmc_restore_bridge_pci_data()
228 ddata->bridge_pci_data.msi_lo); in ls2k_bmc_restore_bridge_pci_data()
229 pci_write_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_HI, in ls2k_bmc_restore_bridge_pci_data()
230 ddata->bridge_pci_data.msi_hi); in ls2k_bmc_restore_bridge_pci_data()
231 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_DEVCTL, in ls2k_bmc_restore_bridge_pci_data()
232 ddata->bridge_pci_data.devctl); in ls2k_bmc_restore_bridge_pci_data()
233 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, in ls2k_bmc_restore_bridge_pci_data()
234 ddata->bridge_pci_data.linkcap); in ls2k_bmc_restore_bridge_pci_data()
235 pci_write_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, in ls2k_bmc_restore_bridge_pci_data()
236 ddata->bridge_pci_data.linkctl_sts); in ls2k_bmc_restore_bridge_pci_data()
238 pci_write_config_dword(parent, LS7A_GEN2_CTL, ddata->bridge_pci_data.gen2_ctrl); in ls2k_bmc_restore_bridge_pci_data()
239 pci_write_config_dword(parent, LS7A_SYMBOL_TIMER, ddata->bridge_pci_data.symbol_timer); in ls2k_bmc_restore_bridge_pci_data()
245 struct pci_dev *pdev = to_pci_dev(ddata->dev); in ls2k_bmc_recover_pci_data()
246 struct pci_dev *parent = pdev->bus->self; in ls2k_bmc_recover_pci_data()
250 * Clear the bus, io and mem resources of the PCI-E bridge to zero, so that in ls2k_bmc_recover_pci_data()
251 * the processor can not access the LS2K PCI-E port, to avoid crashing due to in ls2k_bmc_recover_pci_data()
252 * the lack of return signal from accessing the LS2K PCI-E port. in ls2k_bmc_recover_pci_data()
259 * When the LS2K BMC is reset, the LS7A PCI-E port is also reset, and its PCI in ls2k_bmc_recover_pci_data()
260 * BAR0 register is cleared. Due to the time gap between the GPIO interrupt in ls2k_bmc_recover_pci_data()
261 * generation and the LS2K BMC reset, the LS7A PCI BAR0 register is read to in ls2k_bmc_recover_pci_data()
264 for (i = LS7A_BAR0_CHECK_MAX_TIMES; i > 0 ; i--) { in ls2k_bmc_recover_pci_data()
275 /* Check if PCI-E is connected */ in ls2k_bmc_recover_pci_data()
279 /* Waiting for U-Boot and DDR ready */ in ls2k_bmc_recover_pci_data()
284 /* Restore LS2K BMC PCI-E config data */ in ls2k_bmc_recover_pci_data()
285 pci_write_config_dword(pdev, PCI_COMMAND, ddata->bmc_pci_data.pci_command); in ls2k_bmc_recover_pci_data()
286 pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, ddata->bmc_pci_data.base_address0); in ls2k_bmc_recover_pci_data()
287 pci_write_config_dword(pdev, PCI_INTERRUPT_LINE, ddata->bmc_pci_data.interrupt_line); in ls2k_bmc_recover_pci_data()
297 * The PCI-E is lost when the BMC resets, at which point access to the PCI-E in ls2k_bmc_events_fn()
303 /* Re-push the display due to previous PCI-E loss. */ in ls2k_bmc_events_fn()
304 set_console(vt_move_to_console(MAX_NR_CONSOLES - 1, 1)); in ls2k_bmc_events_fn()
318 schedule_work(&ddata->bmc_reset_work); in ls2k_bmc_interrupt()
331 struct pci_dev *parent = pdev->bus->self; in ls2k_bmc_save_pci_data()
334 pci_read_config_dword(parent, PCI_COMMAND, &ddata->bridge_pci_data.pci_command); in ls2k_bmc_save_pci_data()
337 pci_read_config_dword(parent, base, &ddata->bridge_pci_data.base_address[i]); in ls2k_bmc_save_pci_data()
339 pci_read_config_dword(parent, PCI_ROM_ADDRESS, &ddata->bridge_pci_data.rom_addreess); in ls2k_bmc_save_pci_data()
340 pci_read_config_dword(parent, PCI_INTERRUPT_LINE, &ddata->bridge_pci_data.interrupt_line); in ls2k_bmc_save_pci_data()
342 pci_read_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_LO, in ls2k_bmc_save_pci_data()
343 &ddata->bridge_pci_data.msi_lo); in ls2k_bmc_save_pci_data()
344 pci_read_config_dword(parent, parent->msi_cap + PCI_MSI_ADDRESS_HI, in ls2k_bmc_save_pci_data()
345 &ddata->bridge_pci_data.msi_hi); in ls2k_bmc_save_pci_data()
347 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_DEVCTL, in ls2k_bmc_save_pci_data()
348 &ddata->bridge_pci_data.devctl); in ls2k_bmc_save_pci_data()
349 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCAP, in ls2k_bmc_save_pci_data()
350 &ddata->bridge_pci_data.linkcap); in ls2k_bmc_save_pci_data()
351 pci_read_config_dword(parent, parent->pcie_cap + PCI_EXP_LNKCTL, in ls2k_bmc_save_pci_data()
352 &ddata->bridge_pci_data.linkctl_sts); in ls2k_bmc_save_pci_data()
354 pci_read_config_dword(parent, LS7A_GEN2_CTL, &ddata->bridge_pci_data.gen2_ctrl); in ls2k_bmc_save_pci_data()
355 ddata->bridge_pci_data.gen2_ctrl |= FIELD_PREP(LS7A_GEN2_SPEED_CHANG, 0x1) | in ls2k_bmc_save_pci_data()
358 pci_read_config_dword(parent, LS7A_SYMBOL_TIMER, &ddata->bridge_pci_data.symbol_timer); in ls2k_bmc_save_pci_data()
359 ddata->bridge_pci_data.symbol_timer |= LS7A_MASK_LEN_MATCH; in ls2k_bmc_save_pci_data()
361 pci_read_config_dword(pdev, PCI_COMMAND, &ddata->bmc_pci_data.pci_command); in ls2k_bmc_save_pci_data()
362 pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &ddata->bmc_pci_data.base_address0); in ls2k_bmc_save_pci_data()
363 pci_read_config_dword(pdev, PCI_INTERRUPT_LINE, &ddata->bmc_pci_data.interrupt_line); in ls2k_bmc_save_pci_data()
368 struct pci_dev *pdev = to_pci_dev(ddata->dev); in ls2k_bmc_init()
374 INIT_WORK(&ddata->bmc_reset_work, ls2k_bmc_events_fn); in ls2k_bmc_init()
376 ret = devm_request_irq(&pdev->dev, pdev->irq, ls2k_bmc_interrupt, in ls2k_bmc_init()
379 dev_err(ddata->dev, "Failed to request LS2KBMC PCI-E IRQ %d.\n", pdev->irq); in ls2k_bmc_init()
385 return -ENOMEM; in ls2k_bmc_init()
387 /* Disable GPIO output */ in ls2k_bmc_init()
391 /* Enable GPIO functionality */ in ls2k_bmc_init()
395 /* Set GPIO interrupts to low-level active */ in ls2k_bmc_init()
399 /* Enable GPIO interrupts */ in ls2k_bmc_init()
406 * Since gpio_chip->to_irq is not implemented in the Loongson-3 GPIO driver, in ls2k_bmc_init()
407 * acpi_register_gsi() is used to obtain the GPIO IRQ. The GPIO interrupt is a in ls2k_bmc_init()
415 ret = devm_request_irq(ddata->dev, gpio_irq, ls2k_bmc_interrupt, in ls2k_bmc_init()
416 IRQF_SHARED | IRQF_TRIGGER_FALLING, "ls2kbmc gpio", ddata); in ls2k_bmc_init()
418 dev_err(ddata->dev, "Failed to request LS2KBMC GPIO IRQ %d.\n", gpio_irq); in ls2k_bmc_init()
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.
434 mode = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0) + SZ_16M, SZ_16M); in ls2k_bmc_parse_mode()
436 return -ENOMEM; in ls2k_bmc_parse_mode()
442 ret = kstrtoint(strsep(&mode, "x"), 10, &pd->width); in ls2k_bmc_parse_mode()
446 ret = kstrtoint(strsep(&mode, "-"), 10, &pd->height); in ls2k_bmc_parse_mode()
454 pd->stride = pd->width * depth / 8; in ls2k_bmc_parse_mode()
455 pd->format = depth == 32 ? "a8r8g8b8" : "r5g6b5"; in ls2k_bmc_parse_mode()
471 ddata = devm_kzalloc(&dev->dev, sizeof(*ddata), GFP_KERNEL); in ls2k_bmc_probe()
473 ret = -ENOMEM; in ls2k_bmc_probe()
477 ddata->dev = &dev->dev; in ls2k_bmc_probe()
489 base = dev->resource[0].start + LS2K_DISPLAY_RES_START; in ls2k_bmc_probe()
492 ret = aperture_remove_conflicting_devices(base, SZ_4M, "simple-framebuffer"); in ls2k_bmc_probe()
494 dev_err(&dev->dev, "Failed to removed firmware framebuffers: %d\n", ret); in ls2k_bmc_probe()
498 ret = devm_mfd_add_devices(&dev->dev, PLATFORM_DEVID_AUTO, in ls2k_bmc_probe()
500 &dev->resource[0], 0, NULL); in ls2k_bmc_probe()
523 .name = "ls2k-bmc",
530 MODULE_DESCRIPTION("Loongson-2K Board Management Controller (BMC) Core driver");