Commit 7324a7a0d5e232551eedad69fea3e4b91973d7c6
1 parent
77dfece2e6
bus: ti-sysc: Implement display subsystem reset quirk
The display subsystem (DSS) needs the child outputs disabled for reset. In order to prepare to probe DSS without legacy platform data, let's implement sysc_pre_reset_quirk_dss() similar to what we have for the platform data with omap_dss_reset(). Note that we cannot directly use the old omap_dss_reset() without platform data callbacks and updating omap_dss_reset() to understand struct device. And we will be dropping omap_dss_reset() anyways when all the SoCs are probing with device tree, so let's not mess with the legacy code at all. Cc: Jyri Sarha <jsarha@ti.com> Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Showing 2 changed files with 129 additions and 3 deletions Side-by-side Diff
drivers/bus/ti-sysc.c
... | ... | @@ -1303,11 +1303,11 @@ |
1303 | 1303 | SYSC_QUIRK("dcan", 0x48480000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, |
1304 | 1304 | SYSC_QUIRK_CLKDM_NOAUTO), |
1305 | 1305 | SYSC_QUIRK("dss", 0x4832a000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, |
1306 | - SYSC_QUIRK_OPT_CLKS_IN_RESET), | |
1306 | + SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | |
1307 | 1307 | SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000040, 0xffffffff, |
1308 | - SYSC_QUIRK_OPT_CLKS_IN_RESET), | |
1308 | + SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | |
1309 | 1309 | SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000061, 0xffffffff, |
1310 | - SYSC_QUIRK_OPT_CLKS_IN_RESET), | |
1310 | + SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | |
1311 | 1311 | SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, |
1312 | 1312 | SYSC_QUIRK_CLKDM_NOAUTO), |
1313 | 1313 | SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, |
... | ... | @@ -1468,6 +1468,128 @@ |
1468 | 1468 | } |
1469 | 1469 | } |
1470 | 1470 | |
1471 | +/* | |
1472 | + * DSS needs dispc outputs disabled to reset modules. Returns mask of | |
1473 | + * enabled DSS interrupts. Eventually we may be able to do this on | |
1474 | + * dispc init rather than top-level DSS init. | |
1475 | + */ | |
1476 | +static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, | |
1477 | + bool disable) | |
1478 | +{ | |
1479 | + bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false; | |
1480 | + const int lcd_en_mask = BIT(0), digit_en_mask = BIT(1); | |
1481 | + int manager_count; | |
1482 | + bool framedonetv_irq; | |
1483 | + u32 val, irq_mask = 0; | |
1484 | + | |
1485 | + switch (sysc_soc->soc) { | |
1486 | + case SOC_2420 ... SOC_3630: | |
1487 | + manager_count = 2; | |
1488 | + framedonetv_irq = false; | |
1489 | + break; | |
1490 | + case SOC_4430 ... SOC_4470: | |
1491 | + manager_count = 3; | |
1492 | + break; | |
1493 | + case SOC_5430: | |
1494 | + case SOC_DRA7: | |
1495 | + manager_count = 4; | |
1496 | + break; | |
1497 | + case SOC_AM4: | |
1498 | + manager_count = 1; | |
1499 | + break; | |
1500 | + case SOC_UNKNOWN: | |
1501 | + default: | |
1502 | + return 0; | |
1503 | + }; | |
1504 | + | |
1505 | + /* Remap the whole module range to be able to reset dispc outputs */ | |
1506 | + devm_iounmap(ddata->dev, ddata->module_va); | |
1507 | + ddata->module_va = devm_ioremap(ddata->dev, | |
1508 | + ddata->module_pa, | |
1509 | + ddata->module_size); | |
1510 | + if (!ddata->module_va) | |
1511 | + return -EIO; | |
1512 | + | |
1513 | + /* DISP_CONTROL */ | |
1514 | + val = sysc_read(ddata, dispc_offset + 0x40); | |
1515 | + lcd_en = val & lcd_en_mask; | |
1516 | + digit_en = val & digit_en_mask; | |
1517 | + if (lcd_en) | |
1518 | + irq_mask |= BIT(0); /* FRAMEDONE */ | |
1519 | + if (digit_en) { | |
1520 | + if (framedonetv_irq) | |
1521 | + irq_mask |= BIT(24); /* FRAMEDONETV */ | |
1522 | + else | |
1523 | + irq_mask |= BIT(2) | BIT(3); /* EVSYNC bits */ | |
1524 | + } | |
1525 | + if (disable & (lcd_en | digit_en)) | |
1526 | + sysc_write(ddata, dispc_offset + 0x40, | |
1527 | + val & ~(lcd_en_mask | digit_en_mask)); | |
1528 | + | |
1529 | + if (manager_count <= 2) | |
1530 | + return irq_mask; | |
1531 | + | |
1532 | + /* DISPC_CONTROL2 */ | |
1533 | + val = sysc_read(ddata, dispc_offset + 0x238); | |
1534 | + lcd2_en = val & lcd_en_mask; | |
1535 | + if (lcd2_en) | |
1536 | + irq_mask |= BIT(22); /* FRAMEDONE2 */ | |
1537 | + if (disable && lcd2_en) | |
1538 | + sysc_write(ddata, dispc_offset + 0x238, | |
1539 | + val & ~lcd_en_mask); | |
1540 | + | |
1541 | + if (manager_count <= 3) | |
1542 | + return irq_mask; | |
1543 | + | |
1544 | + /* DISPC_CONTROL3 */ | |
1545 | + val = sysc_read(ddata, dispc_offset + 0x848); | |
1546 | + lcd3_en = val & lcd_en_mask; | |
1547 | + if (lcd3_en) | |
1548 | + irq_mask |= BIT(30); /* FRAMEDONE3 */ | |
1549 | + if (disable && lcd3_en) | |
1550 | + sysc_write(ddata, dispc_offset + 0x848, | |
1551 | + val & ~lcd_en_mask); | |
1552 | + | |
1553 | + return irq_mask; | |
1554 | +} | |
1555 | + | |
1556 | +/* DSS needs child outputs disabled and SDI registers cleared for reset */ | |
1557 | +static void sysc_pre_reset_quirk_dss(struct sysc *ddata) | |
1558 | +{ | |
1559 | + const int dispc_offset = 0x1000; | |
1560 | + int error; | |
1561 | + u32 irq_mask, val; | |
1562 | + | |
1563 | + /* Get enabled outputs */ | |
1564 | + irq_mask = sysc_quirk_dispc(ddata, dispc_offset, false); | |
1565 | + if (!irq_mask) | |
1566 | + return; | |
1567 | + | |
1568 | + /* Clear IRQSTATUS */ | |
1569 | + sysc_write(ddata, 0x1000 + 0x18, irq_mask); | |
1570 | + | |
1571 | + /* Disable outputs */ | |
1572 | + val = sysc_quirk_dispc(ddata, dispc_offset, true); | |
1573 | + | |
1574 | + /* Poll IRQSTATUS */ | |
1575 | + error = readl_poll_timeout(ddata->module_va + dispc_offset + 0x18, | |
1576 | + val, val != irq_mask, 100, 50); | |
1577 | + if (error) | |
1578 | + dev_warn(ddata->dev, "%s: timed out %08x !+ %08x\n", | |
1579 | + __func__, val, irq_mask); | |
1580 | + | |
1581 | + if (sysc_soc->soc == SOC_3430) { | |
1582 | + /* Clear DSS_SDI_CONTROL */ | |
1583 | + sysc_write(ddata, dispc_offset + 0x44, 0); | |
1584 | + | |
1585 | + /* Clear DSS_PLL_CONTROL */ | |
1586 | + sysc_write(ddata, dispc_offset + 0x48, 0); | |
1587 | + } | |
1588 | + | |
1589 | + /* Clear DSS_CONTROL to switch DSS clock sources to PRCM if not */ | |
1590 | + sysc_write(ddata, dispc_offset + 0x40, 0); | |
1591 | +} | |
1592 | + | |
1471 | 1593 | /* 1-wire needs module's internal clocks enabled for reset */ |
1472 | 1594 | static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata) |
1473 | 1595 | { |
... | ... | @@ -1605,6 +1727,9 @@ |
1605 | 1727 | |
1606 | 1728 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS) |
1607 | 1729 | ddata->module_enable_quirk = sysc_module_enable_quirk_aess; |
1730 | + | |
1731 | + if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_DSS_RESET) | |
1732 | + ddata->pre_reset_quirk = sysc_pre_reset_quirk_dss; | |
1608 | 1733 | |
1609 | 1734 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_RTC_UNLOCK) { |
1610 | 1735 | ddata->module_unlock_quirk = sysc_module_unlock_quirk_rtc; |
include/linux/platform_data/ti-sysc.h