19450faf4Sryan_chen // SPDX-License-Identifier: GPL-2.0+
29450faf4Sryan_chen /*
39450faf4Sryan_chen * Copyright (C) ASPEED Technology Inc.
49450faf4Sryan_chen */
59450faf4Sryan_chen
68dd9ccd8SJammy Huang #include <linux/bitfield.h>
79450faf4Sryan_chen #include <common.h>
89450faf4Sryan_chen #include <clk.h>
99450faf4Sryan_chen #include <dm.h>
109450faf4Sryan_chen #include <errno.h>
119450faf4Sryan_chen #include <reset.h>
129450faf4Sryan_chen #include <fdtdec.h>
139450faf4Sryan_chen #include <asm/io.h>
149450faf4Sryan_chen #include "dp_mcu_firmware.h"
159450faf4Sryan_chen
168dd9ccd8SJammy Huang #define MCU_CTRL 0x180100e0
178dd9ccd8SJammy Huang #define MCU_CTRL_AHBS_IMEM_EN BIT(0)
188dd9ccd8SJammy Huang #define MCU_CTRL_AHBS_SW_RST BIT(4)
198dd9ccd8SJammy Huang #define MCU_CTRL_AHBM_SW_RST BIT(8)
208dd9ccd8SJammy Huang #define MCU_CTRL_CORE_SW_RST BIT(12)
218dd9ccd8SJammy Huang #define MCU_CTRL_DMEM_SHUT_DOWN BIT(16)
228dd9ccd8SJammy Huang #define MCU_CTRL_DMEM_SLEEP BIT(17)
238dd9ccd8SJammy Huang #define MCU_CTRL_DMEM_CLK_OFF BIT(18)
248dd9ccd8SJammy Huang #define MCU_CTRL_IMEM_SHUT_DOWN BIT(20)
258dd9ccd8SJammy Huang #define MCU_CTRL_IMEM_SLEEP BIT(21)
268dd9ccd8SJammy Huang #define MCU_CTRL_IMEM_CLK_OFF BIT(22)
278dd9ccd8SJammy Huang #define MCU_CTRL_IMEM_SEL BIT(24)
288dd9ccd8SJammy Huang #define MCU_CTRL_CONFIG BIT(28)
298dd9ccd8SJammy Huang
308dd9ccd8SJammy Huang #define MCU_INTR_CTRL 0x180100e8
318dd9ccd8SJammy Huang #define MCU_INTR_CTRL_CLR GENMASK(7, 0)
328dd9ccd8SJammy Huang #define MCU_INTR_CTRL_MASK GENMASK(15, 8)
338dd9ccd8SJammy Huang #define MCU_INTR_CTRL_EN GENMASK(23, 16)
348dd9ccd8SJammy Huang
358dd9ccd8SJammy Huang #define MCU_IMEM_START 0x18020000
36f07c2791SJammy Huang
379450faf4Sryan_chen struct aspeed_dp_priv {
389450faf4Sryan_chen void *ctrl_base;
399450faf4Sryan_chen };
409450faf4Sryan_chen
_redriver_cfg(struct udevice * dev)41*d99caab4SJammy Huang static void _redriver_cfg(struct udevice *dev)
42*d99caab4SJammy Huang {
43*d99caab4SJammy Huang const u32 *cell;
44*d99caab4SJammy Huang int i, len;
45*d99caab4SJammy Huang u32 tmp;
46*d99caab4SJammy Huang
47*d99caab4SJammy Huang // update configs to dmem for re-driver
48*d99caab4SJammy Huang writel(0x0000dead, 0x18000e00); // mark re-driver cfg not ready
49*d99caab4SJammy Huang cell = dev_read_prop(dev, "eq-table", &len);
50*d99caab4SJammy Huang if (cell) {
51*d99caab4SJammy Huang for (i = 0; i < len / sizeof(u32); ++i)
52*d99caab4SJammy Huang writel(fdt32_to_cpu(cell[i]), 0x18000e04 + i * 4);
53*d99caab4SJammy Huang } else {
54*d99caab4SJammy Huang debug("%s(): Failed to get eq-table for re-driver\n", __func__);
55*d99caab4SJammy Huang return;
56*d99caab4SJammy Huang }
57*d99caab4SJammy Huang
58*d99caab4SJammy Huang tmp = dev_read_s32_default(dev, "i2c-base-addr", -1);
59*d99caab4SJammy Huang if (tmp == -1) {
60*d99caab4SJammy Huang debug("%s(): Failed to get i2c port's base address\n", __func__);
61*d99caab4SJammy Huang return;
62*d99caab4SJammy Huang }
63*d99caab4SJammy Huang writel(tmp, 0x18000e28);
64*d99caab4SJammy Huang
65*d99caab4SJammy Huang tmp = dev_read_s32_default(dev, "i2c-buf-addr", -1);
66*d99caab4SJammy Huang if (tmp == -1) {
67*d99caab4SJammy Huang debug("%s(): Failed to get i2c port's buf address\n", __func__);
68*d99caab4SJammy Huang return;
69*d99caab4SJammy Huang }
70*d99caab4SJammy Huang writel(tmp, 0x18000e2c);
71*d99caab4SJammy Huang
72*d99caab4SJammy Huang tmp = dev_read_s32_default(dev, "dev-addr", -1);
73*d99caab4SJammy Huang if (tmp == -1)
74*d99caab4SJammy Huang tmp = 0x70;
75*d99caab4SJammy Huang writel(tmp, 0x18000e30);
76*d99caab4SJammy Huang writel(0x0000cafe, 0x18000e00); // mark re-driver cfg ready
77*d99caab4SJammy Huang }
78*d99caab4SJammy Huang
aspeed_dp_probe(struct udevice * dev)799450faf4Sryan_chen static int aspeed_dp_probe(struct udevice *dev)
809450faf4Sryan_chen {
819450faf4Sryan_chen struct aspeed_dp_priv *dp = dev_get_priv(dev);
829450faf4Sryan_chen struct reset_ctl dp_reset_ctl, dpmcu_reset_ctrl;
83*d99caab4SJammy Huang int i, ret = 0;
84*d99caab4SJammy Huang u32 mcu_ctrl;
856875160cSJammy Huang bool is_mcu_stop = ((readl(0x1e6e2100) & BIT(13)) == 0);
869450faf4Sryan_chen
879450faf4Sryan_chen /* Get the controller base address */
889450faf4Sryan_chen dp->ctrl_base = (void *)devfdt_get_addr_index(dev, 0);
899450faf4Sryan_chen
909450faf4Sryan_chen debug("%s(dev=%p) \n", __func__, dev);
919450faf4Sryan_chen
929450faf4Sryan_chen ret = reset_get_by_index(dev, 0, &dp_reset_ctl);
939450faf4Sryan_chen if (ret) {
949450faf4Sryan_chen printf("%s(): Failed to get dp reset signal\n", __func__);
959450faf4Sryan_chen return ret;
969450faf4Sryan_chen }
979450faf4Sryan_chen
989450faf4Sryan_chen ret = reset_get_by_index(dev, 1, &dpmcu_reset_ctrl);
999450faf4Sryan_chen if (ret) {
1009450faf4Sryan_chen printf("%s(): Failed to get dp mcu reset signal\n", __func__);
1019450faf4Sryan_chen return ret;
1029450faf4Sryan_chen }
1039450faf4Sryan_chen
104f7347bb7SJammy Huang /* reset for DPTX and DPMCU if MCU isn't running */
1056875160cSJammy Huang if (is_mcu_stop) {
1069450faf4Sryan_chen reset_assert(&dp_reset_ctl);
1079450faf4Sryan_chen reset_assert(&dpmcu_reset_ctrl);
1089450faf4Sryan_chen reset_deassert(&dp_reset_ctl);
1099450faf4Sryan_chen reset_deassert(&dpmcu_reset_ctrl);
110f7347bb7SJammy Huang }
1119450faf4Sryan_chen
1129450faf4Sryan_chen /* select HOST or BMC as display control master
1139450faf4Sryan_chen enable or disable sending EDID to Host */
1149450faf4Sryan_chen writel(readl(dp->ctrl_base + 0xB8) & ~(BIT(24) | BIT(28)), dp->ctrl_base + 0xB8);
1159450faf4Sryan_chen
1169450faf4Sryan_chen /* DPMCU */
1179450faf4Sryan_chen /* clear display format and enable region */
1189450faf4Sryan_chen writel(0, 0x18000de0);
1199450faf4Sryan_chen
120*d99caab4SJammy Huang _redriver_cfg(dev);
121*d99caab4SJammy Huang
1229450faf4Sryan_chen /* load DPMCU firmware to internal instruction memory */
1236875160cSJammy Huang if (is_mcu_stop) {
1248dd9ccd8SJammy Huang mcu_ctrl = MCU_CTRL_CONFIG | MCU_CTRL_IMEM_CLK_OFF | MCU_CTRL_IMEM_SHUT_DOWN |
1258dd9ccd8SJammy Huang MCU_CTRL_DMEM_CLK_OFF | MCU_CTRL_DMEM_SHUT_DOWN | MCU_CTRL_AHBS_SW_RST;
1268dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1278dd9ccd8SJammy Huang
1288dd9ccd8SJammy Huang mcu_ctrl &= ~(MCU_CTRL_IMEM_SHUT_DOWN | MCU_CTRL_DMEM_SHUT_DOWN);
1298dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1308dd9ccd8SJammy Huang
1318dd9ccd8SJammy Huang mcu_ctrl &= ~(MCU_CTRL_IMEM_CLK_OFF | MCU_CTRL_DMEM_CLK_OFF);
1328dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1338dd9ccd8SJammy Huang
1348dd9ccd8SJammy Huang mcu_ctrl |= MCU_CTRL_AHBS_IMEM_EN;
1358dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1369450faf4Sryan_chen
1379450faf4Sryan_chen for (i = 0; i < ARRAY_SIZE(firmware_ast2600_dp); i++)
1388dd9ccd8SJammy Huang writel(firmware_ast2600_dp[i], MCU_IMEM_START + (i * 4));
1399450faf4Sryan_chen
1409450faf4Sryan_chen /* release DPMCU internal reset */
1418dd9ccd8SJammy Huang mcu_ctrl &= ~MCU_CTRL_AHBS_IMEM_EN;
1428dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1438dd9ccd8SJammy Huang mcu_ctrl |= MCU_CTRL_CORE_SW_RST | MCU_CTRL_AHBM_SW_RST;
1448dd9ccd8SJammy Huang writel(mcu_ctrl, MCU_CTRL);
1453d9e9a33Sryan_chen //disable dp interrupt
1468dd9ccd8SJammy Huang writel(FIELD_PREP(MCU_INTR_CTRL_EN, 0xff), MCU_INTR_CTRL);
1476875160cSJammy Huang }
1486875160cSJammy Huang
1493d9e9a33Sryan_chen //set vga ASTDP with DPMCU FW handling scratch
1503d9e9a33Sryan_chen writel(readl(0x1e6e2100) | (0x7 << 9), 0x1e6e2100);
1519450faf4Sryan_chen
1529450faf4Sryan_chen return 0;
1539450faf4Sryan_chen }
1549450faf4Sryan_chen
dp_aspeed_ofdata_to_platdata(struct udevice * dev)1559450faf4Sryan_chen static int dp_aspeed_ofdata_to_platdata(struct udevice *dev)
1569450faf4Sryan_chen {
1579450faf4Sryan_chen struct aspeed_dp_priv *dp = dev_get_priv(dev);
1589450faf4Sryan_chen
1599450faf4Sryan_chen /* Get the controller base address */
1609450faf4Sryan_chen dp->ctrl_base = (void *)devfdt_get_addr_index(dev, 0);
1619450faf4Sryan_chen
1629450faf4Sryan_chen return 0;
1639450faf4Sryan_chen }
1649450faf4Sryan_chen
1659450faf4Sryan_chen static const struct udevice_id aspeed_dp_ids[] = {
1669450faf4Sryan_chen { .compatible = "aspeed,ast2600-displayport" },
1679450faf4Sryan_chen { }
1689450faf4Sryan_chen };
1699450faf4Sryan_chen
1709450faf4Sryan_chen U_BOOT_DRIVER(aspeed_dp) = {
1719450faf4Sryan_chen .name = "aspeed_dp",
1729450faf4Sryan_chen .id = UCLASS_MISC,
1739450faf4Sryan_chen .of_match = aspeed_dp_ids,
1749450faf4Sryan_chen .probe = aspeed_dp_probe,
1759450faf4Sryan_chen .ofdata_to_platdata = dp_aspeed_ofdata_to_platdata,
1769450faf4Sryan_chen .priv_auto_alloc_size = sizeof(struct aspeed_dp_priv),
1779450faf4Sryan_chen };
178