source "drivers/gpu/drm/img-rogue/Kconfig"
+source "drivers/gpu/drm/spacemit/Kconfig"
+
config DRM_HYPERV
tristate "DRM Support for Hyper-V synthetic video device"
depends on DRM && PCI && MMU && HYPERV
obj-$(CONFIG_DRM_SPRD) += sprd/
obj-$(CONFIG_DRM_LOONGSON) += loongson/
obj-$(CONFIG_POWERVR_ROGUE) += img-rogue/
+obj-$(CONFIG_DRM_SPACEMIT) += spacemit/
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0
+
+config DRM_SPACEMIT
+ tristate "DRM Support for Spacemit"
+ select DRM
+ select DRM_KMS_HELPER
+ select DRM_GEM_CMA_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_MIPI_DSI
+ select DRM_PANEL
+ select VIDEOMODE_HELPERS
+ select BACKLIGHT_CLASS_DEVICE
+ select GKI_FIX_WORKAROUND if DRM_SPACEMIT=m
+ default n
+ help
+ Choose this option if you have a Spacemit soc chipsets.
+ This driver provides Spacemit kernel mode
+ setting and buffer management. If M is selected the module will be called spacemit-drm.
+
+config SPACEMIT_MIPI_PANEL
+ tristate "MIPI Panel Support For Spacemit"
+ depends on DRM_SPACEMIT
+
+config SPACEMIT_HDMI
+ tristate "HDMI Support For Spacemit"
+ depends on DRM_SPACEMIT
+
+config DRM_LT8911EXB
+ tristate "Lontium LT8911EXB DSI to eDP"
+ default y
+ depends on DRM_SPACEMIT
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ select DRM_PANEL
+ select DRM_MIPI_DSI
+ select AUXILIARY_BUS
+ select DRM_DP_AUX_BUS
+
+ help
+ Support for Lontium LT8911EXB DSI to eDP driver.
+
+config DRM_LT9711
+ tristate "Lontium LT9711 DSI to DP"
+ default y
+ depends on DRM_SPACEMIT
+ select DRM_KMS_HELPER
+ select REGMAP_I2C
+ select DRM_PANEL
+ select DRM_MIPI_DSI
+ select AUXILIARY_BUS
+ select DRM_DP_AUX_BUS
+
+ help
+ Support for Lontium LT9711 DSI to eDP driver.
\ No newline at end of file
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0
+
+spacemit-drm-y := spacemit_drm.o \
+ spacemit_cmdlist.o \
+ spacemit_dpu.o \
+ spacemit_planes.o \
+ spacemit_dsi.o \
+ spacemit_wb.o \
+ spacemit_dphy.o \
+ spacemit_lib.o \
+ spacemit_gem.o \
+ spacemit_dmmu.o \
+ spacemit_bootloader.o \
+ sysfs/sysfs_class.o \
+ sysfs/sysfs_dpu.o \
+ sysfs/sysfs_dsi.o \
+ sysfs/sysfs_dphy.o \
+ sysfs/sysfs_mipi_panel.o \
+ dpu/dpu_debug.o \
+ dpu/dpu_saturn.o \
+ dpu/saturn_fbcmem.o \
+ dsi/spacemit_dsi_drv.o \
+ dsi/spacemit_dptc_drv.o \
+ dphy/spacemit_dphy_drv.o
+
+
+obj-$(CONFIG_DRM_SPACEMIT) += spacemit-drm.o
+
+obj-$(CONFIG_SPACEMIT_MIPI_PANEL) += spacemit_mipi_panel.o
+obj-$(CONFIG_SPACEMIT_HDMI) += spacemit_hdmi.o
+obj-$(CONFIG_DRM_LT8911EXB) += lt8911exb.o
+obj-$(CONFIG_DRM_LT9711) += lt9711.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "../dsi/spacemit_dsi_hw.h"
+#include "../spacemit_dphy.h"
+#include "../dsi/spacemit_dptc_drv.h"
+
+static unsigned int spacemit_dphy_lane[5] = {0, 0x1, 0x3, 0x7, 0xf};
+
+static void dphy_ana_reset(void __iomem *base_addr)
+{
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+ udelay(5);
+ dsi_set_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+}
+
+static void dphy_set_power(void __iomem *base_addr, bool poweron)
+{
+ if(poweron) {
+ dsi_set_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+ dsi_set_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_PU);
+ } else {
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_PU);
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_PWR_CTRL, CFG_DPHY_ANA_RESET);
+ }
+}
+
+static void dphy_set_cont_clk(void __iomem *base_addr, bool cont_clk)
+{
+#ifdef DPTC_DPHY_TEST
+ uint32_t tmp;
+
+ if(cont_clk) {
+ tmp = dptc_dsi_read(0x04);
+ tmp |= CFG_DPHY_CONT_CLK;
+ //dptc_dsi_write(0x04, tmp);
+ } else {
+ tmp = dptc_dsi_read(0x04);
+ tmp &= (~CFG_DPHY_CONT_CLK);
+ //dptc_dsi_write(0x04, tmp);
+ }
+ dptc_dsi_write(0x04, 0x30001);
+#else
+ if(cont_clk)
+ dsi_set_bits(base_addr, DSI_PHY_CTRL_1, CFG_DPHY_CONT_CLK);
+ else
+ dsi_clear_bits(base_addr, DSI_PHY_CTRL_1, CFG_DPHY_CONT_CLK);
+
+ dsi_set_bits(base_addr, DSI_PHY_CTRL_1, CFG_DPHY_ADD_VALID);
+ dsi_set_bits(base_addr, DSI_PHY_CTRL_1, CFG_DPHY_VDD_VALID);
+#endif
+}
+
+static void dphy_set_lane_num(void __iomem *base_addr, uint32_t lane_num)
+{
+#ifdef DPTC_DPHY_TEST
+ uint32_t tmp;
+
+ tmp = dptc_dsi_read(0x08);
+ tmp &= ~CFG_DPHY_LANE_EN_MASK;
+ tmp |= spacemit_dphy_lane[lane_num] << CFG_DPHY_LANE_EN_SHIFT;
+ dptc_dsi_write(0x08, 0);
+ tmp = dptc_dsi_read(0x08);
+ dptc_dsi_write(0x08, 0x30);
+#endif
+ dsi_write_bits(base_addr, DSI_PHY_CTRL_2,
+ CFG_DPHY_LANE_EN_MASK, spacemit_dphy_lane[lane_num] << CFG_DPHY_LANE_EN_SHIFT);
+}
+
+static void dphy_set_bit_clk_src(void __iomem *base_addr, uint32_t bit_clk_src,
+ uint32_t half_pll5)
+{
+#ifdef DPTC_DPHY_TEST
+ uint32_t tmp;
+#endif
+
+ if(bit_clk_src >= DPHY_BIT_CLK_SRC_MAX) {
+ pr_err("%s: Invalid bit clk src (%d)\n", __func__, bit_clk_src);
+ return;
+ }
+
+#ifdef DPTC_DPHY_TEST
+ //if(bit_clk_src == DPHY_BIT_CLK_SRC_MUX) {
+ if(0) {
+ tmp = dptc_dsi_read(0x68);
+ tmp |= CFG_CLK_SEL;
+ dptc_dsi_write(0x68,tmp);
+ } else {
+ tmp = dptc_dsi_read(0x68);
+ tmp &= ~CFG_CLK_SEL;
+ dptc_dsi_write(0x68,tmp);
+ }
+
+ //if(1 == half_pll5) {
+ if(0) {
+ tmp = dptc_dsi_read(0x68);
+ tmp |= CFG_CLK_DIV2;
+ dptc_dsi_write(0x68,tmp);
+ } else {
+ tmp = dptc_dsi_read(0x68);
+ tmp &= ~CFG_CLK_DIV2;
+ dptc_dsi_write(0x68,tmp);
+ }
+#else
+#if 0
+ if(bit_clk_src == DPHY_BIT_CLK_SRC_MUX)
+ dsi_set_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_SEL);
+ else
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_SEL);
+
+ if(1 == half_pll5)
+ dsi_set_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_DIV2);
+ else
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_DIV2);
+#else
+ /*
+ dsi_set_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_SEL);
+ dsi_clear_bits(base_addr, DSI_PHY_ANA_CTRL1, CFG_CLK_DIV2);
+ */
+#endif
+#endif
+}
+
+static void dphy_set_timing(struct spacemit_dphy_ctx *dphy_ctx)
+{
+ uint32_t bitclk, lpx_clk, lpx_time, ta_get, ta_go;
+ int ui, wakeup, reg;
+ int hs_prep, hs_zero, hs_trail, hs_exit, ck_zero, ck_trail, ck_exit;
+ int esc_clk, esc_clk_t;
+ struct spacemit_dphy_timing *phy_timing;
+ uint32_t value;
+
+ if(NULL == dphy_ctx) {
+ pr_err("%s: Invalid param!\n", __func__);
+ return;
+ }
+
+ phy_timing = &(dphy_ctx->dphy_timing);
+
+ DRM_DEBUG("%s() phy_freq %d esc_clk %d \n", __func__, dphy_ctx->phy_freq, dphy_ctx->esc_clk);
+
+ esc_clk = dphy_ctx->esc_clk/1000;
+ esc_clk_t = 1000/esc_clk;
+
+ bitclk = dphy_ctx->phy_freq / 1000;
+ ui = 1000/bitclk + 1;
+
+ lpx_clk = (phy_timing->lpx_constant + phy_timing->lpx_ui * ui) / esc_clk_t + 1;
+ lpx_time = lpx_clk * esc_clk_t;
+
+ /* Below is for NT35451 */
+ ta_get = lpx_time * 5 / esc_clk_t - 1;
+ ta_go = lpx_time * 4 / esc_clk_t - 1;
+
+ wakeup = phy_timing->wakeup_constant;
+ wakeup = wakeup / esc_clk_t + 1;
+
+ hs_prep = phy_timing->hs_prep_constant + phy_timing->hs_prep_ui * ui;
+ hs_prep = hs_prep / esc_clk_t + 1;
+
+ /* Our hardware added 3-byte clk automatically.
+ * 3-byte 3 * 8 * ui.
+ */
+ hs_zero = phy_timing->hs_zero_constant + phy_timing->hs_zero_ui * ui -
+ (hs_prep + 1) * esc_clk_t;
+ hs_zero = (hs_zero - (3 * ui << 3)) / esc_clk_t + 4;
+ if (hs_zero < 0)
+ hs_zero = 0;
+
+ hs_trail = phy_timing->hs_trail_constant + phy_timing->hs_trail_ui * ui;
+ hs_trail = ((8 * ui) >= hs_trail) ? (8 * ui) : hs_trail;
+ hs_trail = hs_trail / esc_clk_t + 1;
+ if (hs_trail > 3)
+ hs_trail -= 3;
+ else
+ hs_trail = 0;
+
+ hs_exit = phy_timing->hs_exit_constant + phy_timing->hs_exit_ui * ui;
+ hs_exit = hs_exit / esc_clk_t + 1;
+
+ ck_zero = phy_timing->ck_zero_constant + phy_timing->ck_zero_ui * ui -
+ (hs_prep + 1) * esc_clk_t;
+ ck_zero = ck_zero / esc_clk_t + 1;
+
+ ck_trail = phy_timing->ck_trail_constant + phy_timing->ck_trail_ui * ui;
+ ck_trail = ck_trail / esc_clk_t + 1;
+
+ ck_exit = hs_exit;
+
+ reg = (hs_exit << CFG_DPHY_TIME_HS_EXIT_SHIFT)
+ | (hs_trail << CFG_DPHY_TIME_HS_TRAIL_SHIFT)
+ | (hs_zero << CFG_DPHY_TIME_HS_ZERO_SHIFT)
+ | (hs_prep << CFG_DPHY_TIME_HS_PREP_SHIFT);
+
+ DRM_DEBUG("%s dphy time0 hs_exit %d hs_trail %d hs_zero %d hs_prep %d reg 0x%x\n", __func__, hs_exit, hs_trail, hs_zero, hs_prep, reg);
+#ifdef DPTC_DPHY_TEST
+ dptc_dsi_write(0x40 , 0x01000000);
+#else
+ dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_0, reg);
+ // dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_0, 0x06010603);
+#endif
+
+ reg = (ta_get << CFG_DPHY_TIME_TA_GET_SHIFT)
+ | (ta_go << CFG_DPHY_TIME_TA_GO_SHIFT)
+ | (wakeup << CFG_DPHY_TIME_WAKEUP_SHIFT);
+
+ DRM_DEBUG("%s dphy time1 ta_get %d ta_go %d wakeup %d reg 0x%x\n", __func__, ta_get, ta_go, wakeup, reg);
+#ifdef DPTC_DPHY_TEST
+ dptc_dsi_write(0x44, 0x0403001F);
+#else
+ dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_1, reg);
+ // dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_1, 0x130fcd98);
+#endif
+ reg = (ck_exit << CFG_DPHY_TIME_CLK_EXIT_SHIFT)
+ | (ck_trail << CFG_DPHY_TIME_CLK_TRAIL_SHIFT)
+ | (ck_zero << CFG_DPHY_TIME_CLK_ZERO_SHIFT)
+ | (lpx_clk << CFG_DPHY_TIME_CLK_LPX_SHIFT);
+
+ DRM_DEBUG("%s dphy time2 ck_exit %d ck_trail %d ck_zero %d lpx_clk %d reg 0x%x\n", __func__, ck_exit, ck_trail, ck_zero, lpx_clk, reg);
+#ifdef DPTC_DPHY_TEST
+ dptc_dsi_write(0x48, 0x02010500);
+#else
+ dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_2, reg);
+ // dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_2, 0x06040c04);
+#endif
+
+ reg = (lpx_clk << CFG_DPHY_TIME_LPX_SHIFT)
+ | phy_timing->req_ready << CFG_DPHY_TIME_REQRDY_SHIFT;
+
+ DRM_DEBUG("%s dphy time3 lpx_clk %d req_ready %d reg 0x%x\n", __func__, lpx_clk, phy_timing->req_ready, reg);
+#ifdef DPTC_DPHY_TEST
+ dptc_dsi_write(0x4c, 0x001F);
+#else
+ dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_3, reg);
+ // dsi_write(dphy_ctx->base_addr, DSI_PHY_TIME_3, 0x43c);
+#endif
+ /* calculated timing on brownstone:
+ * DSI_PHY_TIME_0 0x06080204
+ * DSI_PHY_TIME_1 0x6d2bfff0
+ * DSI_PHY_TIME_2 0x603130a
+ * DSI_PHY_TIME_3 0xa3c
+ */
+
+ value = dsi_read(dphy_ctx->base_addr, DSI_PHY_TIME_0);
+ DRM_DEBUG("%s() DSI_PHY_TIME_0 offset 0x%x value 0x%x\n", __func__, DSI_PHY_TIME_0, value);
+ value = dsi_read(dphy_ctx->base_addr, DSI_PHY_TIME_1);
+ DRM_DEBUG("%s() DSI_PHY_TIME_1 offset 0x%x value 0x%x\n", __func__, DSI_PHY_TIME_1, value);
+ value = dsi_read(dphy_ctx->base_addr, DSI_PHY_TIME_2);
+ DRM_DEBUG("%s() DSI_PHY_TIME_2 offset 0x%x value 0x%x\n", __func__, DSI_PHY_TIME_2, value);
+ value = dsi_read(dphy_ctx->base_addr, DSI_PHY_TIME_3);
+ DRM_DEBUG("%s() DSI_PHY_TIME_3 offset 0x%x value 0x%x\n", __func__, DSI_PHY_TIME_3, value);
+}
+
+static void dphy_get_setting(struct spacemit_dphy_ctx *dphy_ctx, struct device_node *np)
+{
+ struct spacemit_dphy_timing *dphy_timing = &dphy_ctx->dphy_timing;
+ int ret;
+
+ if(NULL == dphy_timing){
+ pr_err("%s: Invalid param\n",__func__);
+ return;
+ }
+
+ ret = of_property_read_u32(np, "hs_prep_constant", &dphy_timing->hs_prep_constant);
+ if(0 != ret)
+ dphy_timing->hs_prep_constant = HS_PREP_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_prep_ui", &dphy_timing->hs_prep_ui);
+ if(0 != ret)
+ dphy_timing->hs_prep_ui = HS_PREP_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_zero_constant", &dphy_timing->hs_zero_constant);
+ if(0 != ret)
+ dphy_timing->hs_zero_constant = HS_ZERO_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_zero_ui", &dphy_timing->hs_zero_ui);
+ if(0 != ret)
+ dphy_timing->hs_zero_ui = HS_ZERO_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_trail_constant", &dphy_timing->hs_trail_constant);
+ if(0 != ret)
+ dphy_timing->hs_trail_constant = HS_TRAIL_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_trail_ui", &dphy_timing->hs_trail_ui);
+ if(0 != ret)
+ dphy_timing->hs_trail_ui = HS_TRAIL_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_exit_constant", &dphy_timing->hs_exit_constant);
+ if(0 != ret)
+ dphy_timing->hs_exit_constant = HS_EXIT_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "hs_exit_ui", &dphy_timing->hs_exit_ui);
+ if(0 != ret)
+ dphy_timing->hs_exit_ui = HS_EXIT_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "ck_zero_constant", &dphy_timing->ck_zero_constant);
+ if(0 != ret)
+ dphy_timing->ck_zero_constant = CK_ZERO_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "ck_zero_ui", &dphy_timing->ck_zero_ui);
+ if(0 != ret)
+ dphy_timing->ck_zero_ui = CK_ZERO_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "ck_trail_constant", &dphy_timing->ck_trail_constant);
+ if(0 != ret)
+ dphy_timing->ck_trail_constant = CK_TRAIL_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "ck_zero_ui", &dphy_timing->ck_zero_ui);
+ if(0 != ret)
+ dphy_timing->ck_zero_ui = CK_TRAIL_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "req_ready", &dphy_timing->req_ready);
+ if(0 != ret)
+ dphy_timing->req_ready = REQ_READY_DEFAULT;
+
+ ret = of_property_read_u32(np, "wakeup_constant", &dphy_timing->wakeup_constant);
+ if(0 != ret)
+ dphy_timing->wakeup_constant = WAKEUP_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "wakeup_ui", &dphy_timing->wakeup_ui);
+ if(0 != ret)
+ dphy_timing->wakeup_ui = WAKEUP_UI_DEFAULT;
+
+ ret = of_property_read_u32(np, "lpx_constant", &dphy_timing->lpx_constant);
+ if(0 != ret)
+ dphy_timing->lpx_constant = LPX_CONSTANT_DEFAULT;
+
+ ret = of_property_read_u32(np, "lpx_ui", &dphy_timing->lpx_ui);
+ if(0 != ret)
+ dphy_timing->lpx_ui = LPX_UI_DEFAULT;
+}
+
+
+void spacemit_dphy_core_get_status(struct spacemit_dphy_ctx *dphy_ctx)
+{
+ pr_debug("%s\n", __func__);
+
+ if(NULL == dphy_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return;
+ }
+
+ dphy_ctx->dphy_status0 = dsi_read(dphy_ctx->base_addr, DSI_PHY_STATUS_0);
+ dphy_ctx->dphy_status1 = dsi_read(dphy_ctx->base_addr, DSI_PHY_STATUS_1);
+ dphy_ctx->dphy_status2 = dsi_read(dphy_ctx->base_addr, DSI_PHY_STATUS_2);
+ pr_debug("%s: dphy_status0 = 0x%x\n", __func__, dphy_ctx->dphy_status0);
+ pr_debug("%s: dphy_status1 = 0x%x\n", __func__, dphy_ctx->dphy_status1);
+ pr_debug("%s: dphy_status2 = 0x%x\n", __func__, dphy_ctx->dphy_status2);
+}
+
+void spacemit_dphy_core_reset(struct spacemit_dphy_ctx *dphy_ctx)
+{
+ pr_debug("%s\n", __func__);
+
+ if(NULL == dphy_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return;
+ }
+
+ dphy_ana_reset(dphy_ctx->base_addr);
+}
+
+/**
+ * spacemit_dphy_core_init - int spacemit dphy
+ *
+ * @dphy_ctx: pointer to the spacemit_dphy_ctx
+ *
+ * This function will be called by the dsi driver in order to init the dphy
+ * This function will do phy power on, enable continous clk, set dphy timing
+ * and set lane number.
+ *
+ * This function has no return value.
+ *
+ */
+void spacemit_dphy_core_init(struct spacemit_dphy_ctx *dphy_ctx)
+{
+ pr_debug("%s\n", __func__);
+
+ if(NULL == dphy_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return;
+ }
+
+ if(DPHY_STATUS_UNINIT != dphy_ctx->status){
+ pr_warn("%s: dphy_ctx has been initialized (%d)\n",
+ __func__, dphy_ctx->status);
+ return;
+ }
+
+ /*use DPHY_BIT_CLK_SRC_MUX as default clk src*/
+ dphy_set_bit_clk_src(dphy_ctx->base_addr, dphy_ctx->clk_src, dphy_ctx->half_pll5);
+
+ /* digital and analog power on */
+ dphy_set_power(dphy_ctx->base_addr, true);
+
+ /* turn on DSI continuous clock for HS */
+ dphy_set_cont_clk(dphy_ctx->base_addr, true);
+
+ /* set dphy */
+ dphy_set_timing(dphy_ctx);
+
+ /* enable data lanes */
+ dphy_set_lane_num(dphy_ctx->base_addr, dphy_ctx->lane_num);
+
+ dphy_ctx->status = DPHY_STATUS_INIT;
+}
+
+/**
+ * spacemit_dphy_core_uninit - unint spacemit dphy
+ *
+ * @dphy_ctx: pointer to the spacemit_dphy_ctx
+ *
+ * This function will be called by the dsi driver in order to unint the dphy
+ * This function will disable continous clk, reset dphy, power down dphy
+ *
+ * This function has no return value.
+ *
+ */
+void spacemit_dphy_core_uninit(struct spacemit_dphy_ctx *dphy_ctx)
+{
+ pr_debug("%s\n", __func__);
+
+ if(NULL == dphy_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return;
+ }
+
+ if(DPHY_STATUS_INIT != dphy_ctx->status){
+ pr_warn("%s: dphy_ctx has not been initialized (%d)\n",
+ __func__, dphy_ctx->status);
+ return;
+ }
+
+ dphy_set_cont_clk(dphy_ctx->base_addr, false);
+ dphy_ana_reset(dphy_ctx->base_addr);
+ dphy_set_power(dphy_ctx->base_addr, false);
+
+ dphy_ctx->status = DPHY_STATUS_UNINIT;
+}
+
+int spacemit_dphy_core_parse_dt(struct spacemit_dphy_ctx *dphy_ctx, struct device_node *np)
+{
+ if (!dphy_ctx) {
+ pr_err("%s: Param is NULL\n",__func__);
+ return -1;
+ }
+
+ dphy_get_setting(dphy_ctx, np);
+
+ return 0;
+}
+
+
+static struct dphy_core_ops dphy_core_ops = {
+ .parse_dt = spacemit_dphy_core_parse_dt,
+ .init = spacemit_dphy_core_init,
+ .uninit = spacemit_dphy_core_uninit,
+ .reset = spacemit_dphy_core_reset,
+ .get_status = spacemit_dphy_core_get_status,
+};
+
+static struct ops_entry entry = {
+ .ver = "spacemit-dphy",
+ .ops = &dphy_core_ops,
+};
+
+static int __init dphy_core_register(void)
+{
+ return dphy_core_ops_register(&entry);
+}
+
+subsys_initcall(dphy_core_register);
+
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/trace_events.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_framebuffer.h>
+#include "dpu_debug.h"
+#include "dpu_trace.h"
+#include "./../spacemit_dpu_reg.h"
+#include "./../spacemit_drm.h"
+
+dpu_reg_enum SATURN_LE_DPU_REG_ENUM_LISTS[] = {
+ E_DPU_TOP_REG,
+ E_DPU_CTRL_REG,
+ E_DPU_CTRL_REG,
+ E_DPU_CMDLIST_REG,
+ E_DPU_INT_REG,
+ E_DMA_TOP_CTRL_REG,
+ E_RDMA_LAYER0_REG,
+ E_RDMA_LAYER1_REG,
+ E_RDMA_LAYER2_REG,
+ E_RDMA_LAYER3_REG,
+ E_MMU_TBU0_REG,
+ E_MMU_TBU2_REG,
+ E_MMU_TBU4_REG,
+ E_MMU_TBU6_REG,
+ E_COMPOSER2_REG,
+ E_SCALER0_REG,
+ E_OUTCTRL2_REG
+};
+
+static dpu_reg_dump_t dpu_reg_dump_array[] = {
+ {E_DPU_TOP_REG, "DPU_TOP", DPU_TOP_BASE_ADDR, 218},
+
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR, 5},
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR + 0x24, 8},
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR + 0x54, 8},
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR + 0x84, 19},
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR + 0xe4, 8},
+ {E_DPU_CTRL_REG, "DPU_CTRL", DPU_CTRL_BASE_ADDR + 0x114, 25},
+
+ {E_DPU_CRG_REG, "DPU_CRG", DPU_CRG_BASE_ADDR, 5},
+
+ {E_DPU_CMDLIST_REG, "DPU_CMDLIST", CMDLIST_BASE_ADDR, 44},
+
+ {E_DPU_INT_REG, "DPU_INT", DPU_INT_BASE_ADDR, 40},
+
+ {E_DMA_TOP_CTRL_REG, "DMA_TOP_CTRL", DMA_TOP_BASE_ADDR, 25},
+
+ {E_RDMA_LAYER0_REG, "RDMA_LAYER0", RDMA0_BASE_ADDR, 31},
+ {E_RDMA_LAYER0_REG, "RDMA_LAYER0", RDMA0_BASE_ADDR + 0x80, 57},
+
+ {E_RDMA_LAYER1_REG, "RDMA_LAYER1", RDMA1_BASE_ADDR, 31},
+ {E_RDMA_LAYER1_REG, "RDMA_LAYER1", RDMA1_BASE_ADDR + 0x80, 57},
+
+ {E_RDMA_LAYER2_REG, "RDMA_LAYER2", RDMA2_BASE_ADDR, 31},
+ {E_RDMA_LAYER2_REG, "RDMA_LAYER2", RDMA2_BASE_ADDR + 0x80, 57},
+
+ {E_RDMA_LAYER3_REG, "RDMA_LAYER3" ,RDMA3_BASE_ADDR, 31},
+ {E_RDMA_LAYER3_REG, "RDMA_LAYER3", RDMA3_BASE_ADDR + 0x80, 57},
+
+ {E_RDMA_LAYER4_REG, "RDMA_LAYER4", RDMA4_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER5_REG, "RDMA_LAYER5", RDMA5_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER6_REG, "RDMA_LAYER6", RDMA6_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER7_REG, "RDMA_LAYER7", RDMA7_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER8_REG, "RDMA_LAYER8", RDMA8_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER9_REG, "RDMA_LAYER9", RDMA9_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER10_REG, "RDMA_LAYER10", RDMA10_BASE_ADDR, 46},
+
+ {E_RDMA_LAYER11_REG, "RDMA_LAYER11", RDMA11_BASE_ADDR, 46},
+
+ {E_MMU_TBU0_REG, "MMU_TBU0", MMU_TBU_BASE_ADDR + 0 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU1_REG, "MMU_TBU1", MMU_TBU_BASE_ADDR + 1 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU2_REG, "MMU_TBU2", MMU_TBU_BASE_ADDR + 2 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU3_REG, "MMU_TBU3", MMU_TBU_BASE_ADDR + 3 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU4_REG, "MMU_TBU4", MMU_TBU_BASE_ADDR + 4 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU5_REG, "MMU_TBU5", MMU_TBU_BASE_ADDR + 5 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU6_REG, "MMU_TBU6", MMU_TBU_BASE_ADDR + 6 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU7_REG, "MMU_TBU7", MMU_TBU_BASE_ADDR + 7 * MMU_TBU_SIZE, 13},
+ {E_MMU_TBU8_REG, "MMU_TBU8", MMU_TBU_BASE_ADDR + 8 * MMU_TBU_SIZE, 13},
+ {E_MMU_TOP_REG, "MMU_TOP", MMU_TOP_BASE_ADDR, 13},
+
+ {E_LP0_REG, "LP0", LP0_BASE_ADDR, 81},
+ {E_LP1_REG, "LP1", LP1_BASE_ADDR, 81},
+ {E_LP2_REG, "LP2", LP2_BASE_ADDR, 81},
+ {E_LP3_REG, "LP3", LP3_BASE_ADDR, 81},
+ {E_LP4_REG, "LP4", LP4_BASE_ADDR, 81},
+ {E_LP5_REG, "LP5", LP5_BASE_ADDR, 81},
+ {E_LP6_REG, "LP6", LP6_BASE_ADDR, 81},
+ {E_LP7_REG, "LP7", LP7_BASE_ADDR, 81},
+ {E_LP8_REG, "LP8", LP8_BASE_ADDR, 81},
+ {E_LP9_REG, "LP9", LP9_BASE_ADDR, 81},
+ {E_LP10_REG, "LP10", LP10_BASE_ADDR, 81},
+ {E_LP11_REG, "LP11", LP11_BASE_ADDR, 81},
+
+ {E_LM0_REG, "LMERGE0", LMERGE0_BASE_ADDR, 4},
+ {E_LM1_REG, "LMERGE1", LMERGE1_BASE_ADDR, 4},
+ {E_LM2_REG, "LMERGE2", LMERGE2_BASE_ADDR, 4},
+ {E_LM3_REG, "LMERGE3", LMERGE3_BASE_ADDR, 4},
+ {E_LM4_REG, "LMERGE4", LMERGE4_BASE_ADDR, 4},
+ {E_LM5_REG, "LMERGE5", LMERGE5_BASE_ADDR, 4},
+ {E_LM6_REG, "LMERGE6", LMERGE6_BASE_ADDR, 4},
+ {E_LM7_REG, "LMERGE7", LMERGE7_BASE_ADDR, 4},
+ {E_LM8_REG, "LMERGE8", LMERGE8_BASE_ADDR, 4},
+ {E_LM9_REG, "LMERGE9", LMERGE9_BASE_ADDR, 4},
+ {E_LM10_REG, "LMERGE10", LMERGE10_BASE_ADDR, 4},
+ {E_LM11_REG, "LMERGE11", LMERGE11_BASE_ADDR, 4},
+
+ {E_COMPOSER0_REG, "COMPOSER0", CMP0_BASE_ADDR, 146},
+ {E_COMPOSER1_REG, "COMPOSER1", CMP1_BASE_ADDR, 146},
+ {E_COMPOSER2_REG, "COMPOSER2", CMP2_BASE_ADDR, 146},
+ {E_COMPOSER3_REG, "COMPOSER3", CMP3_BASE_ADDR, 146},
+
+ {E_SCALER0_REG, "SCALER0", SCALER0_ONLINE_BASE_ADDR, 121},
+ {E_SCALER1_REG, "SCALER1", SCALER1_ONLINE_BASE_ADDR, 121},
+
+ {E_OUTCTRL0_REG, "OUTCTRL0", OUTCTRL0_BASE_ADDR, 55},
+ {E_PP0_REG, "PP0", PP0_BASE_ADDR, 86},
+ {E_OUTCTRL1_REG, "OUTCTRL1", OUTCTRL1_BASE_ADDR, 55},
+ {E_PP1_REG, "PP1", PP1_BASE_ADDR, 86},
+ {E_OUTCTRL2_REG, "OUTCTRL2", OUTCTRL2_BASE_ADDR, 55},
+ {E_PP2_REG, "PP2", PP2_BASE_ADDR, 86},
+ {E_OUTCTRL3_REG, "OUTCTRL3", OUTCTRL3_BASE_ADDR, 55},
+ {E_PP3_REG, "PP3", PP3_BASE_ADDR, 86},
+
+ {E_WB_TOP_0_REG, "WB_TOP_0", WB0_TOP_BASE_ADDR, 54},
+ {E_WB_TOP_1_REG, "WB_TOP_1", WB1_TOP_BASE_ADDR, 54},
+};
+
+static void dump_dpu_regs_by_enum(void __iomem *io_base, phys_addr_t phy_base, dpu_reg_enum reg_enum, u8 trace_dump)
+{
+ int i;
+ int j;
+ uint32_t reg_num;
+ void __iomem *io_addr;
+ phys_addr_t phy_addr;
+
+ dpu_reg_dump_t *tmp = &dpu_reg_dump_array[0];
+
+ for (i = 0; i < ARRAY_SIZE(dpu_reg_dump_array); i++) {
+ if (tmp->index == reg_enum) {
+ reg_num = tmp->dump_reg_num;
+ io_addr = io_base + tmp->module_offset;
+ phy_addr = phy_base + tmp->module_offset;
+ if (trace_dump) {
+ trace_dpu_reg_info(tmp->module_name, phy_addr, reg_num);
+ for (j = 0; j < reg_num; j++) {
+ trace_dpu_reg_dump(phy_addr + j * 4, readl(io_addr + j * 4));
+ }
+ } else {
+ printk(KERN_DEBUG "%d-%s, address:0x%08llx, num:%d\n", tmp->index, tmp->module_name, phy_addr, reg_num);
+ for (j = 0; j < reg_num; j++) {
+ printk(KERN_DEBUG "0x%08llx: 0x%08x\n", (phy_addr + j * 4), readl(io_addr + j * 4));
+ }
+ }
+ }
+ tmp++;
+ }
+}
+
+bool dpu_reg_enum_valid(dpu_reg_enum reg_enum)
+{
+ int size = ARRAY_SIZE(SATURN_LE_DPU_REG_ENUM_LISTS);
+ int i = 0;
+
+ for (i = 0; i < size; i++) {
+ if (reg_enum == SATURN_LE_DPU_REG_ENUM_LISTS[i])
+ return true;
+ }
+
+ return false;
+}
+
+void dump_dpu_regs(struct spacemit_dpu *dpu, dpu_reg_enum reg_enum, u8 trace_dump)
+{
+ dpu_reg_enum tmp = E_DPU_TOP_REG;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ void __iomem* reg_io_base = hwdev->base;
+ phys_addr_t reg_phy_base = hwdev->phy_addr;
+
+ if (reg_enum > E_DPU_DUMP_ALL) {
+ pr_err("invalid dump regsiter enum\n");
+ return;
+ } else if (reg_enum == E_DPU_DUMP_ALL) {
+ for (; tmp < E_DPU_DUMP_ALL; tmp++) {
+ if (dpu_reg_enum_valid(tmp))
+ dump_dpu_regs_by_enum(reg_io_base, reg_phy_base, tmp, trace_dump);
+ }
+ } else {
+ dump_dpu_regs_by_enum(reg_io_base, reg_phy_base, reg_enum, trace_dump);
+ }
+}
+
+static void dpu_debug_mode(struct spacemit_hw_device *hwdev, int pipeline_id, bool enable)
+{
+ u32 base = DPU_CTRL_BASE_ADDR;
+
+ switch (pipeline_id) {
+ case ONLINE0:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl0_dbg_mod, enable ? 1 : 0);
+ break;
+ case ONLINE1:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl1_dbg_mod, enable ? 1 : 0);
+ break;
+ case ONLINE2:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl2_dbg_mod, enable ? 1 : 0);
+ break;
+ case OFFLINE0:
+ case OFFLINE1:
+ default:
+ DRM_ERROR("pipeline id is invalid!\n");
+ break;
+ }
+}
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+static struct file *gki_filp_open(const char *filename, int flags, umode_t mode)
+{
+ return 0;
+}
+static ssize_t gki_kernel_write(struct file *file, const void *buf, size_t count,
+ loff_t *pos)
+{
+ return 0;
+}
+#endif
+#define DPU_BUFFER_DUMP_FILE "/mnt/dpu_buffer_dump"
+int dpu_buffer_dump(struct drm_plane *plane) {
+ unsigned int buffer_size = 0;
+ int i = 0;
+ void *mmu_tbl_vaddr = NULL;
+ phys_addr_t dpu_buffer_paddr = 0;
+ void __iomem *dpu_buffer_vaddr = NULL;
+ loff_t pos = 0;
+ static int dump_once = true;
+ struct file *filep = NULL;
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(plane->state);
+
+ if (!dump_once)
+ return 0;
+
+ mmu_tbl_vaddr = spacemit_pstate->mmu_tbl.va;
+ buffer_size = plane->state->fb->obj[0]->size >> PAGE_SHIFT;
+
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+ filep = gki_filp_open(DPU_BUFFER_DUMP_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
+#else
+ filep = filp_open(DPU_BUFFER_DUMP_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
+#endif
+
+ if (IS_ERR(filep)) {
+ printk("Open file %s error\n", DPU_BUFFER_DUMP_FILE);
+ return -EINVAL;
+ }
+ for (i = 0; i < buffer_size; i++) {
+ dpu_buffer_paddr = *(volatile u32 __force *)mmu_tbl_vaddr;
+ dpu_buffer_paddr = dpu_buffer_paddr << PAGE_SHIFT;
+ if (dpu_buffer_paddr >= 0x80000000UL) {
+ dpu_buffer_paddr += 0x80000000UL;
+ }
+ dpu_buffer_vaddr = phys_to_virt((unsigned long)dpu_buffer_paddr);
+ mmu_tbl_vaddr += 4;
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+ gki_kernel_write(filep, (void *)dpu_buffer_vaddr, PAGE_SIZE, &pos);
+#else
+ kernel_write(filep, (void *)dpu_buffer_vaddr, PAGE_SIZE, &pos);
+#endif
+ }
+
+ filp_close(filep, NULL);
+ filep = NULL;
+
+ dump_once = false;
+
+ return 0;
+}
+
+void dpu_dump_reg(struct spacemit_dpu *dpu)
+{
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ if (!dpu->enable_dump_reg)
+ return;
+
+ dpu_debug_mode(hwdev, ONLINE2, 1);
+ dump_dpu_regs(dpu, E_DPU_DUMP_ALL, 1);
+ dpu_debug_mode(hwdev, ONLINE2, 0);
+}
+
+void dpu_dump_fps(struct spacemit_dpu *dpu)
+{
+ struct timespec64 cur_tm, tmp_tm;
+
+ if (!dpu->enable_dump_fps)
+ return;
+
+ ktime_get_real_ts64(&cur_tm);
+ tmp_tm = timespec64_sub(cur_tm, dpu->last_tm);
+ dpu->last_tm.tv_sec = cur_tm.tv_sec;
+ dpu->last_tm.tv_nsec = cur_tm.tv_nsec;
+ if (tmp_tm.tv_sec == 0)
+ trace_printk("fps: %ld\n", 1000000000 / (tmp_tm.tv_nsec / 1000));
+}
+
+void dpu_underrun_wq_stop_trace(struct work_struct *work)
+{
+// #ifndef MODULE
+// trace_set_clr_event("dpu", NULL, false);
+// #endif
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _DPU_DEBUG_H_
+#define _DPU_DEBUG_H_
+
+#include <linux/types.h>
+#include "saturn_regs/reg_map.h"
+#include "./../spacemit_dpu.h"
+
+typedef enum {
+ E_DPU_TOP_REG = 0,
+ E_DPU_CTRL_REG,
+ E_DPU_CRG_REG,
+ E_DPU_CMDLIST_REG,
+ E_DPU_INT_REG,
+
+ E_DMA_TOP_CTRL_REG,
+ E_RDMA_LAYER0_REG,
+ E_RDMA_LAYER1_REG,
+ E_RDMA_LAYER2_REG,
+ E_RDMA_LAYER3_REG,
+ E_RDMA_LAYER4_REG,
+ E_RDMA_LAYER5_REG,
+ E_RDMA_LAYER6_REG,
+ E_RDMA_LAYER7_REG,
+ E_RDMA_LAYER8_REG,
+ E_RDMA_LAYER9_REG,
+ E_RDMA_LAYER10_REG,
+ E_RDMA_LAYER11_REG,
+
+ E_MMU_TBU0_REG,
+ E_MMU_TBU1_REG,
+ E_MMU_TBU2_REG,
+ E_MMU_TBU3_REG,
+ E_MMU_TBU4_REG,
+ E_MMU_TBU5_REG,
+ E_MMU_TBU6_REG,
+ E_MMU_TBU7_REG,
+ E_MMU_TBU8_REG,
+ E_MMU_TOP_REG,
+
+ E_LP0_REG,
+ E_LP1_REG,
+ E_LP2_REG,
+ E_LP3_REG,
+ E_LP4_REG,
+ E_LP5_REG,
+ E_LP6_REG,
+ E_LP7_REG,
+ E_LP8_REG,
+ E_LP9_REG,
+ E_LP10_REG,
+ E_LP11_REG,
+
+ E_LM0_REG,
+ E_LM1_REG,
+ E_LM2_REG,
+ E_LM3_REG,
+ E_LM4_REG,
+ E_LM5_REG,
+ E_LM6_REG,
+ E_LM7_REG,
+ E_LM8_REG,
+ E_LM9_REG,
+ E_LM10_REG,
+ E_LM11_REG,
+
+ E_COMPOSER0_REG,
+ E_COMPOSER1_REG,
+ E_COMPOSER2_REG,
+ E_COMPOSER3_REG,
+
+ E_SCALER0_REG,
+ E_SCALER1_REG,
+
+ E_OUTCTRL0_REG,
+ E_PP0_REG,
+ E_OUTCTRL1_REG,
+ E_PP1_REG,
+ E_OUTCTRL2_REG,
+ E_PP2_REG,
+ E_OUTCTRL3_REG,
+ E_PP3_REG,
+
+ E_WB_TOP_0_REG,
+ E_WB_TOP_1_REG,
+
+ E_DPU_DUMP_ALL
+}dpu_reg_enum;
+
+typedef struct dpu_reg_dump {
+ dpu_reg_enum index;
+ u8* module_name;
+ uint32_t module_offset;
+ uint32_t dump_reg_num;
+}dpu_reg_dump_t;
+
+void dump_dpu_regs(struct spacemit_dpu *dpu, dpu_reg_enum reg_enum, u8 trace_dump);
+void dpu_dump_reg(struct spacemit_dpu *dpu);
+void dpu_dump_fps(struct spacemit_dpu *dpu);
+int dpu_buffer_dump(struct drm_plane *plane);
+void dpu_underrun_wq_stop_trace(struct work_struct *work);
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/pm_qos.h>
+#include <linux/regmap.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_gem.h>
+#include <drm/drm_writeback.h>
+#include "dpu_saturn.h"
+#include "saturn_fbcmem.h"
+#include "../spacemit_cmdlist.h"
+#include "../spacemit_dmmu.h"
+#include "../spacemit_dpu_reg.h"
+#include "../spacemit_drm.h"
+#include "../spacemit_wb.h"
+#include <video/display_timing.h>
+#include <dt-bindings/display/spacemit-dpu.h>
+
+#define CREATE_TRACE_POINTS
+#include "dpu_trace.h"
+#include "dpu_debug.h"
+
+#define TOTAL_RDMA_MEMSIZE (68 * 1024) /* 68KB */
+#define YUV2RGB_COEFFS 12
+
+//RDMA_FMT_YUV_420_P1_8, RDMA_FMT_YUV_420_P1_10 not support by hardware, has checked with asic
+//rdma hardware support RDMA_FMT_BGRA_16161616/RDMA_FMT_RGBA_16161616 formats are not support by fourcc
+static const struct dpu_format_id primary_fmts[] = {
+ { DRM_FORMAT_ABGR2101010, 1, 32 }, //RDMA_FMT_ABGR_2101010
+ { DRM_FORMAT_ARGB8888, 4, 32 }, //RDMA_FMT_ARGB_8888
+ { DRM_FORMAT_ABGR8888, 5, 32 }, //RDMA_FMT_ABGR_8888
+ { DRM_FORMAT_RGBA8888, 6, 32 }, //RDMA_FMT_RGBA_8888
+ { DRM_FORMAT_BGRA8888, 7, 32 }, //RDMA_FMT_BGRA_8888
+ { DRM_FORMAT_XRGB8888, 8, 32 }, //RDMA_FMT_XRGB_8888
+ { DRM_FORMAT_XBGR8888, 9, 32 }, //RDMA_FMT_XBGR_8888
+ { DRM_FORMAT_RGBX8888, 10, 32 }, //RDMA_FMT_RGBX_8888
+ { DRM_FORMAT_BGRX8888, 11, 32 }, //RDMA_FMT_BGRX_8888
+ { DRM_FORMAT_RGB565, 22, 16 }, //RDMA_FMT_RGB_565
+ { DRM_FORMAT_BGR565, 23, 16 }, //RDMA_FMT_BGR_565
+ /*
+ { DRM_FORMAT_ARGB2101010, 0 }, //RDMA_FMT_ARGB_2101010
+ { DRM_FORMAT_RGBA1010102, 2 }, //RDMA_FMT_RGBA_2101010
+ { DRM_FORMAT_BGRA1010102, 3 }, //RDMA_FMT_BGRA_2101010
+ { DRM_FORMAT_RGB888, 12 }, //RDMA_FMT_RGB_888
+ { DRM_FORMAT_BGR888, 13 }, //RDMA_FMT_BGR_888
+ { DRM_FORMAT_RGBA5551, 14 }, //RDMA_FMT_RGBA_5551
+ { DRM_FORMAT_BGRA5551, 15 }, //RDMA_FMT_BGRA_5551
+ { DRM_FORMAT_ABGR1555, 16 }, //RDMA_FMT_ABGR_1555
+ { DRM_FORMAT_ARGB1555, 17 }, //RDMA_FMT_ARGB_1555
+ { DRM_FORMAT_RGBX5551, 18 }, //RDMA_FMT_RGBX_5551
+ { DRM_FORMAT_BGRX5551, 19 }, //RDMA_FMT_BGRX_5551
+ { DRM_FORMAT_XBGR1555, 20 }, //RDMA_FMT_XBGR_1555
+ { DRM_FORMAT_XRGB1555, 21 }, //RDMA_FMT_XRGB_1555
+ { DRM_FORMAT_ARGB16161616F, 24 }, //RDMA_FMT_ARGB_16161616
+ { DRM_FORMAT_ABGR16161616F, 25 }, //RDMA_FMT_ABGR_16161616
+ { DRM_FORMAT_XYUV8888, 32 }, //RDMA_FMT_XYUV_444_P1_8, uv_swap has no corresponding fourcc format
+ { DRM_FORMAT_Y410, 33 }, //RDMA_FMT_XYUV_444_P1_10, uv_swap has no corresponding fourcc format
+ { DRM_FORMAT_YUYV, 34 }, //RDMA_FMT_VYUY_422_P1_8
+ { DRM_FORMAT_YVYU, 34 }, //RDMA_FMT_VYUY_422_P1_8, uv_swap = 1
+ { DRM_FORMAT_UYVY, 35 }, //RDMA_FMT_YVYU_422_P1_8
+ { DRM_FORMAT_VYUY, 35 }, //RDMA_FMT_YVYU_422_P1_8, uv_swap = 1
+ */
+ { DRM_FORMAT_YUV420_8BIT, 37, 12 }, //DRM_FORMAT_YUV420_8BIT for AFBC
+ { DRM_FORMAT_NV12, 37, 12 }, //RDMA_FMT_YUV_420_P2_8
+ /*
+ { DRM_FORMAT_NV21, 37 }, //RDMA_FMT_YUV_420_P2_8, uv_swap = 1
+ { DRM_FORMAT_YUV420, 38 }, //RDMA_FMT_YUV_420_P3_8
+ { DRM_FORMAT_YVU420, 38 }, //RDMA_FMT_YUV_420_P3_8, uv_swap = 1
+ { DRM_FORMAT_YUV420_10BIT, 39 }, //RDMA_FMT_YUV_420_P1_10 //DPU not support, DO NOT use
+ */
+ { DRM_FORMAT_P010, 40, 24 }, //RDMA_FMT_YUV_420_P2_10
+ /*
+ { DRM_FORMAT_Q410, 41 }, //DPU not support
+ { DRM_FORMAT_Q401, 41 }, //DPU not support
+ */
+};
+
+const struct spacemit_hw_rdma saturn_rdmas[] = {
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+};
+
+const u32 saturn_fbcmem_sizes[] = {
+ 68 * 1024,
+ 68 * 1024,
+};
+EXPORT_SYMBOL(saturn_fbcmem_sizes);
+
+const u32 saturn_rdma_fixed_fbcmem_sizes[] = {
+ 34 * 1024,
+ 34 * 1024,
+ 34 * 1024,
+ 34 * 1024,
+};
+
+static const s16
+spacemit_yuv2rgb_coefs[DRM_COLOR_ENCODING_MAX][DRM_COLOR_RANGE_MAX][YUV2RGB_COEFFS] = {
+ [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ 1192, 0, 1635, -223,
+ 1192, -403, -833, 136,
+ 1192, 2065, 0, -277,
+ },
+ [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = {
+ 1024, 0, 1436, -179,
+ 1024, -354, -732, 136,
+ 1024, 1814, 0, -227,
+ },
+ [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ 1192, 0, 1836, -248,
+ 1192, -218, -546, 77,
+ 1192, 2163, 0, -289,
+ },
+ [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = {
+ 1024, 0, 1613, -202,
+ 1024, -192, -479, 84,
+ 1024, 1900, 0, -238,
+ },
+ [DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_LIMITED_RANGE] = {
+ 1196, 0, 1724, -937,
+ 1196, -192, -668, 355,
+ 1196, 2200, 0, -1175,
+ },
+ [DRM_COLOR_YCBCR_BT2020][DRM_COLOR_YCBCR_FULL_RANGE] = {
+ 1024, 0, 1510, -755,
+ 1024, -168, -585, 377,
+ 1024, 1927, 0, -963,
+ }
+};
+
+const struct spacemit_hw_rdma saturn_le_rdmas[] = {
+ /* TODO: set max_yuv_height to 1088 instead of 1080 due to vpu fw issue */
+ {FORMAT_RGB | FORMAT_AFBC, ROTATE_COMMON},
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+ {FORMAT_RGB, ROTATE_COMMON},
+ {FORMAT_RGB | FORMAT_RAW_YUV | FORMAT_AFBC, ROTATE_COMMON | ROTATE_AFBC_90_270},
+};
+
+const u32 saturn_le_fbcmem_sizes[] = {
+ 44544, //43.5k
+ 35712, //34.875k
+};
+EXPORT_SYMBOL(saturn_le_fbcmem_sizes);
+
+const u32 saturn_le_rdma_fixed_fbcmem_sizes[] = {
+ 11776, //43.5k
+ 32 * 1024,
+ 2944, //2.875k
+ 32 * 1024,
+};
+
+static atomic_t mclk_cnt = ATOMIC_INIT(0);;
+bool dpu_mclk_exclusive_get(void)
+{
+ if (0 == atomic_cmpxchg(&mclk_cnt, 0, 1))
+ return true;
+ else
+ return false;
+}
+EXPORT_SYMBOL(dpu_mclk_exclusive_get);
+
+void dpu_mclk_exclusive_put(void)
+{
+ atomic_set(&mclk_cnt, 0);
+}
+EXPORT_SYMBOL(dpu_mclk_exclusive_put);
+
+struct spacemit_hw_device spacemit_dp_devices[DP_MAX_DEVICES] = {
+ [SATURN_HDMI] = {
+ .base = NULL, /* Parsed by dts */
+ .phy_addr = 0x0, /* Parsed by dts */
+ .plane_nums = 8,
+ .rdma_nums = ARRAY_SIZE(saturn_le_rdmas),
+ .rdmas = saturn_le_rdmas,
+ .n_formats = ARRAY_SIZE(primary_fmts),
+ .formats = primary_fmts,
+ .n_fbcmems = ARRAY_SIZE(saturn_le_fbcmem_sizes),
+ .fbcmem_sizes = saturn_le_fbcmem_sizes,
+ .rdma_fixed_fbcmem_sizes = saturn_le_rdma_fixed_fbcmem_sizes,
+ .solid_color_shift = 0,
+ .hdr_coef_size = 135,
+ .scale_coef_size = 48,
+ .is_hdmi = true,
+ },
+ [SATURN_LE] = {
+ .base = NULL, /* Parsed by dts */
+ .phy_addr = 0x0, /* Parsed by dts */
+ .plane_nums = 8,
+ .rdma_nums = ARRAY_SIZE(saturn_le_rdmas),
+ .rdmas = saturn_le_rdmas,
+ .n_formats = ARRAY_SIZE(primary_fmts),
+ .formats = primary_fmts,
+ .n_fbcmems = ARRAY_SIZE(saturn_le_fbcmem_sizes),
+ .fbcmem_sizes = saturn_le_fbcmem_sizes,
+ .rdma_fixed_fbcmem_sizes = saturn_le_rdma_fixed_fbcmem_sizes,
+ .solid_color_shift = 0,
+ .hdr_coef_size = 135,
+ .scale_coef_size = 48,
+ .is_hdmi = false,
+ },
+};
+EXPORT_SYMBOL(spacemit_dp_devices);
+
+static int dpu_parse_dt(struct spacemit_dpu *dpu, struct device_node *np)
+{
+ struct dpu_clk_context *clk_ctx = &dpu->clk_ctx;
+
+ clk_ctx->pxclk = of_clk_get_by_name(np, "pxclk");
+ if (IS_ERR(clk_ctx->pxclk)) {
+ pr_debug("%s, read pxclk failed from dts!\n", __func__);
+ }
+
+ clk_ctx->mclk = of_clk_get_by_name(np, "mclk");
+ if (IS_ERR(clk_ctx->mclk)) {
+ pr_debug("%s, read mclk failed from dts!\n", __func__);
+ }
+
+ clk_ctx->hclk = of_clk_get_by_name(np, "hclk");
+ if (IS_ERR(clk_ctx->hclk)) {
+ pr_debug("%s, read hclk failed from dts!\n", __func__);
+ }
+
+ clk_ctx->escclk = of_clk_get_by_name(np, "escclk");
+ if (IS_ERR(clk_ctx->escclk)) {
+ pr_debug("%s, read escclk failed from dts!\n", __func__);
+ }
+
+ clk_ctx->bitclk = of_clk_get_by_name(np, "bitclk");
+ if (IS_ERR(clk_ctx->bitclk)) {
+ pr_debug("%s, read bitclk failed from dts!\n", __func__);
+ }
+
+ clk_ctx->hmclk = of_clk_get_by_name(np, "hmclk");
+ if (IS_ERR(clk_ctx->hmclk)) {
+ pr_debug("%s, read hmclk failed from dts!\n", __func__);
+ }
+
+ if (of_property_read_u32(np, "spacemit-dpu-min-mclk", &dpu->min_mclk))
+ dpu->min_mclk = DPU_MCLK_DEFAULT;
+
+ if (of_property_read_bool(np, "spacemit-dpu-auto-fc"))
+ dpu->enable_auto_fc = 0;
+
+ if (of_property_read_u32(np, "spacemit-dpu-bitclk", &dpu->bitclk))
+ dpu->bitclk = DPU_BITCLK_DEFAULT;
+
+ if (of_property_read_u32(np, "spacemit-dpu-escclk", &dpu->escclk))
+ dpu->escclk = DPU_ESCCLK_DEFAULT;
+
+ return 0;
+}
+
+
+static unsigned int dpu_get_bpp(u32 format)
+{
+ unsigned int i = 0;
+
+ for(i = 0; i < ARRAY_SIZE(primary_fmts); i++) {
+ if (format == primary_fmts[i].format)
+ return primary_fmts[i].bpp;
+ }
+
+ DRM_ERROR("format 0x%x is not supported!\n", format);
+ return SPACEMIT_DPU_INVALID_FORMAT_ID;
+}
+
+int dpu_calc_plane_mclk_bw(struct drm_plane *plane, \
+ struct drm_plane_state *new_state)
+{
+ /* For some platform without aclk, mclk = max(aclk, mclk) */
+ uint64_t calc_mclk = 0;
+ uint64_t Fpixclk_hblk = 0;
+ struct drm_plane_state *state = NULL;
+ struct drm_crtc *crtc = new_state->crtc;
+ struct drm_display_mode *mode = NULL;
+ struct spacemit_plane_state *spacemit_plane_state = NULL;
+ uint64_t tmp;
+ uint64_t hact = 0;
+ uint64_t fps = 0;
+ bool scl_en = 0;
+
+ struct drm_framebuffer *fb = new_state->fb;
+ const struct drm_format_info *format = fb->format;
+ unsigned int bpp = dpu_get_bpp(format->format);
+ uint64_t calc_bandwidth = 0;
+
+ struct spacemit_dpu *dpu = NULL;
+
+ state = new_state;
+ if (!crtc)
+ return 0;
+
+ dpu = crtc_to_dpu(crtc);
+ if (!dpu->enable_auto_fc)
+ return 0;
+
+ /* prepare calc mclk and bw */
+ mode = &crtc->mode;
+ hact = mode->hdisplay;
+ fps = mode->clock * 1000 / (mode->htotal * (u16)mode->vtotal);
+ spacemit_plane_state = to_spacemit_plane_state(state);
+ scl_en = spacemit_plane_state->use_scl;
+ Fpixclk_hblk = hact * (mode->vtotal) * fps; /* MHZ */
+
+ trace_dpu_fpixclk_hblk(hact, fps, (uint64_t)mode->vtotal, Fpixclk_hblk);
+
+ /* calculate mclk and bandwidth */
+ if (scl_en) {
+ unsigned int C = 0;
+ uint64_t width_ratio = 0; /* (scl_in_width/hact) * 1000000 */
+ uint64_t height_ratio = 0; /* roundup(scl_in_height/scl_out_height) */
+ uint64_t scl_in_width, scl_in_height, scl_out_width, scl_out_height;
+
+ if (state->rotation == DRM_MODE_ROTATE_90 || state->rotation == DRM_MODE_ROTATE_270) {
+ scl_in_width = state->src_h >> 16;
+ scl_in_height = state->src_w >> 16;
+ } else {
+ scl_in_width = state->src_w >> 16;
+ scl_in_height = state->src_h >> 16;
+ }
+
+ scl_out_width = state->crtc_w;
+ scl_out_height = state->crtc_h;
+
+ C = min(2 * scl_in_width / scl_out_width, 4ULL); /* sclaer after rdma */
+ spacemit_plane_state->afbc_effc = 4 / C;
+
+ //width_ratio = scl_in_width * MHZ2HZ / hact;
+ tmp = scl_in_width * MHZ2HZ;
+ do_div(tmp, hact);
+ width_ratio = tmp;
+ height_ratio = DIV_ROUND_UP_ULL(scl_in_height, scl_out_height) * MHZ2HZ;
+ //calc_mclk = Fpixclk_hblk * max(width_ratio, MHZ2HZ) / MHZ2HZ * max(height_ratio, MHZ2HZ) / MHZ2HZ / C;
+ tmp = Fpixclk_hblk * max(width_ratio, MHZ2HZ);
+ do_div(tmp, MHZ2HZ);
+ tmp = tmp * max(height_ratio, MHZ2HZ);
+ do_div(tmp, MHZ2HZ);
+ do_div(tmp, C);
+ calc_mclk = tmp;
+
+ if (calc_mclk > DPU_MCLK_MAX) {
+ DRM_INFO("plane:%d mclk too large %lld\n", state->zpos, calc_mclk);
+ DRM_INFO("hact = %lld, fps = %lld, vtotal = %d, Fpixclk_hblk = %lld\n", hact, fps, (u16)mode->vtotal, Fpixclk_hblk);
+ DRM_INFO("scl_in_width = %lld, scl_in_height = %lld, scl_out_width = %lld, scl_out_height = %lld, bpp = %d, C = %d\n", scl_in_width, scl_in_height, scl_out_width, scl_out_height, bpp, C);
+ return -EINVAL;
+ }
+
+ //calc_bandwidth = Fpixclk_hblk * bpp * width_ratio / MHZ2HZ * height_ratio / MHZ2HZ / 8;
+ tmp = Fpixclk_hblk * bpp * width_ratio;
+ do_div(tmp, MHZ2HZ);
+ tmp = tmp * height_ratio;
+ do_div(tmp, MHZ2HZ);
+ tmp = tmp >> 3;
+ calc_bandwidth = tmp;
+ if (calc_bandwidth > (DPU_MAX_QOS_REQ * MHZ2KHZ)) {
+ DRM_INFO("plane:%d bandwidth too large %lld\n", state->zpos, calc_bandwidth);
+ DRM_INFO("hact = %lld, fps = %lld, vtotal = %d, Fpixclk_hblk = %lld\n", hact, fps, (u16)mode->vtotal, Fpixclk_hblk);
+ DRM_INFO("scl_in_width = %lld, scl_in_height = %lld, scl_out_width = %lld, scl_out_height = %lld, bpp = %d, C = %d\n", scl_in_width, scl_in_height, scl_out_width, scl_out_height, bpp, C);
+ return -EINVAL;
+ }
+ trace_dpu_mclk_scl(scl_in_width, scl_in_height, scl_out_width, scl_out_height, bpp, C, width_ratio, height_ratio);
+ } else {
+ unsigned long img_width = 0;
+
+ if (state->rotation == DRM_MODE_ROTATE_90 || state->rotation == DRM_MODE_ROTATE_270)
+ img_width = state->src_h >> 16;
+ else
+ img_width = state->src_w >> 16;
+
+ trace_u64_data("no scl img_width", img_width);
+ //calc_mclk = ( hact + 32 ) * MHZ2HZ / hact * Fpixclk_hblk / 2 / MHZ2HZ;
+ tmp = ( hact + 32 ) * MHZ2HZ;
+ do_div(tmp, hact);
+ tmp = tmp * Fpixclk_hblk;
+ tmp = tmp >> 1;
+ do_div(tmp, MHZ2HZ);
+ calc_mclk = tmp;
+ if (calc_mclk > DPU_MCLK_MAX) {
+ DRM_INFO("plane:%d mclk too large %lld\n", state->zpos, calc_mclk);
+ DRM_INFO("img_width = %ld\n", img_width);
+ return -EINVAL;
+ }
+ //calc_bandwidth = Fpixclk_hblk * bpp * img_width / hact / 8;
+ tmp = Fpixclk_hblk * bpp * img_width;
+ do_div(tmp, hact);
+ do_div(tmp, 8);
+ calc_bandwidth = tmp;
+ if (calc_bandwidth > (DPU_MAX_QOS_REQ * MHZ2KHZ)) {
+ DRM_INFO("plane:%d bandwidth too large %lld\n", state->zpos, calc_bandwidth);
+ DRM_INFO("img_width = %ld\n", img_width);
+ return -EINVAL;
+ }
+ }
+
+ dpu = crtc_to_dpu(crtc);
+ if (calc_mclk < dpu->min_mclk)
+ calc_mclk = dpu->min_mclk;
+
+ spacemit_plane_state->mclk = calc_mclk;
+
+ /* add some buffer for MMU and AFBC Header */
+ //calc_bandwidth = calc_bandwidth * 108 / 100;
+ tmp = calc_bandwidth * 108;
+ do_div(tmp, 100);
+ calc_bandwidth = tmp;
+ spacemit_plane_state->bw = calc_bandwidth;
+
+ trace_u64_data("plane calc_mclk", calc_mclk);
+ trace_u64_data("plane calc_bw", calc_bandwidth);
+ return 0;
+}
+
+static int dpu_update_clocks(struct spacemit_dpu *dpu, uint64_t mclk)
+{
+ struct dpu_clk_context *clk_ctx = &dpu->clk_ctx;
+ uint64_t cur_mclk = 0;
+ int ret = 0;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ if (!hwdev->is_hdmi) {
+ trace_u64_data("update mclk", mclk);
+ cur_mclk = clk_get_rate(clk_ctx->mclk);
+ if (cur_mclk == mclk)
+ return 0;
+ if (dpu_mclk_exclusive_get()) {
+ ret = clk_set_rate(clk_ctx->mclk, mclk);
+ if (ret) {
+ trace_u64_data("Failed to set mclk", mclk);
+ DRM_ERROR("Failed to set DPU MCLK %lld %d\n", mclk, ret);
+ } else {
+ dpu_mclk_exclusive_put();
+ dpu->cur_mclk = clk_get_rate(clk_ctx->mclk);
+ trace_u64_data("Pass to set mclk", mclk);
+ }
+ } else {
+ if (mclk > dpu->cur_mclk) {
+ trace_u64_data("MCLK using by other module", mclk);
+ DRM_ERROR("Mclk using by other module %lld\n", mclk);
+ } else
+ dpu->cur_mclk = mclk;
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+static int dpu_update_bw(struct spacemit_dpu *dpu, uint64_t bw)
+{
+ uint64_t __maybe_unused tmp;
+
+ trace_u64_data("update bw", bw);
+
+ if (dpu->cur_bw == bw)
+ return 0;
+
+ return 0;
+}
+
+static int dpu_finish_uboot(struct spacemit_dpu *dpu)
+{
+ void __iomem *base;
+ void __iomem *hdmi;
+ u32 value;
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ if (dpu->type == HDMI) {
+ base = (void __iomem *)ioremap(0xC0440000, 0x2A000);
+ hdmi = (void __iomem *)ioremap(0xC0400500, 0x200);
+
+ // hdmi dpu ctl regs
+ writel(0x00, base + 0x560);
+ writel(0x01, base + 0x56c);
+ // writel(0x00, base + 0x58c);
+
+ // hdmi dpu int regs
+ writel(0x00, base + 0x910);
+ writel(0x00, base + 0x938);
+ //writel(0x00, base + 0x960);
+
+ // hdmi close pll clock
+ writel(0x00, hdmi + 0xe4);
+
+ value = readl_relaxed(base + 0x910);
+ DRM_DEBUG("%s hdmi int reg4 0x910:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x938);
+ DRM_DEBUG("%s hdmi int reg14 0x938:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x960);
+ DRM_DEBUG("%s hdmi int reg24 0x960:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x560);
+ DRM_DEBUG("%s hdmi ctl reg24 0x560:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x56c);
+ DRM_DEBUG("%s hdmi ctl reg27 0x56c:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x58c);
+ DRM_DEBUG("%s hdmi ctl reg35 0x58c:0x%x\n", __func__, value);
+
+ udelay(100);
+ iounmap(base);
+ iounmap(hdmi);
+ } else if (dpu->type == DSI) {
+ base = (void __iomem *)ioremap(0xc0340000, 0x2A000);
+
+ // mipi dsi dpu ctl regs
+ writel(0x00, base + 0x560);
+ writel(0x01, base + 0x56c);
+ // writel(0x00, base + 0x58c);
+
+ // mipi dsi dpu int regs
+ writel(0x00, base + 0x910);
+ writel(0x00, base + 0x938);
+ //writel(0x00, base + 0x960);
+
+ value = readl_relaxed(base + 0x910);
+ DRM_DEBUG("%s mipi dsi int reg4 0x910:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x938);
+ DRM_DEBUG("%s mipi dsi int reg14 0x938:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x960);
+ DRM_DEBUG("%s mipi dsi int reg24 0x960:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x560);
+ DRM_DEBUG("%s mipi dsi ctl reg24 0x560:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x56c);
+ DRM_DEBUG("%s mipi dsi ctl reg27 0x56c:0x%x\n", __func__, value);
+ value = readl_relaxed(base + 0x58c);
+ DRM_DEBUG("%s mipi dsi ctl reg35 0x58c:0x%x\n", __func__, value);
+
+ udelay(100);
+ iounmap(base);
+ } else {
+ return 0;
+ }
+
+ return 0;
+}
+
+static int dpu_enable_clocks(struct spacemit_dpu *dpu)
+{
+ struct dpu_clk_context *clk_ctx = &dpu->clk_ctx;
+ struct drm_crtc *crtc = &dpu->crtc;
+ struct drm_display_mode *mode = &crtc->mode;
+ uint64_t clk_val;
+ uint64_t set_clk_val;
+ struct spacemit_drm_private *priv;
+ struct spacemit_hw_device *hwdev;
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ if (dpu->logo_booton) {
+ if (dpu->type == HDMI) {
+ clk_prepare_enable(clk_ctx->hmclk);
+ } else if (dpu->type == DSI) {
+ clk_prepare_enable(clk_ctx->pxclk);
+ clk_prepare_enable(clk_ctx->mclk);
+ clk_prepare_enable(clk_ctx->hclk);
+ clk_prepare_enable(clk_ctx->escclk);
+ clk_prepare_enable(clk_ctx->bitclk);
+ }
+ udelay(10);
+
+ return 0;
+ }
+
+ priv = dpu->crtc.dev->dev_private;
+ hwdev = priv->hwdev;
+
+ if (hwdev->is_hdmi) {
+ clk_prepare_enable(clk_ctx->hmclk);
+
+ clk_val = clk_get_rate(clk_ctx->hmclk);
+ if(clk_val != DPU_MCLK_DEFAULT){
+ clk_val = clk_round_rate(clk_ctx->hmclk, DPU_MCLK_DEFAULT);
+ if (dpu_mclk_exclusive_get()) {
+ clk_set_rate(clk_ctx->hmclk, clk_val);
+ DRM_DEBUG("set hdmi mclk=%lld\n", clk_val);
+ dpu_mclk_exclusive_put();
+ }
+ }
+
+ clk_val = clk_get_rate(clk_ctx->hmclk);
+ DRM_DEBUG("get hdmi mclk=%lld\n", clk_val);
+
+ udelay(10);
+ } else {
+ clk_prepare_enable(clk_ctx->pxclk);
+ clk_prepare_enable(clk_ctx->mclk);
+ clk_prepare_enable(clk_ctx->hclk);
+ clk_prepare_enable(clk_ctx->escclk);
+ clk_prepare_enable(clk_ctx->bitclk);
+
+ set_clk_val = mode->clock * 1000;
+ DRM_INFO("pxclk set_clk_val %lld\n", set_clk_val);
+
+ if (set_clk_val) {
+ set_clk_val = clk_round_rate(clk_ctx->pxclk, set_clk_val);
+ clk_val = clk_get_rate(clk_ctx->pxclk);
+ if(clk_val != set_clk_val){
+ clk_set_rate(clk_ctx->pxclk, set_clk_val);
+ DRM_DEBUG("set pxclk=%lld\n", set_clk_val);
+ }
+ }
+
+ clk_val = clk_get_rate(clk_ctx->mclk);
+ if(clk_val != DPU_MCLK_DEFAULT){
+ clk_val = clk_round_rate(clk_ctx->mclk, DPU_MCLK_DEFAULT);
+ if (dpu_mclk_exclusive_get()) {
+ clk_set_rate(clk_ctx->mclk, clk_val);
+ DRM_DEBUG("set mclk=%lld\n", clk_val);
+ dpu_mclk_exclusive_put();
+ }
+ }
+
+ clk_val = clk_get_rate(clk_ctx->escclk);
+ set_clk_val = dpu->escclk;
+ if(clk_val != set_clk_val){
+ clk_val = clk_round_rate(clk_ctx->escclk, set_clk_val);
+ clk_set_rate(clk_ctx->escclk, clk_val);
+ DRM_DEBUG("set escclk=%lld\n", clk_val);
+ }
+
+ clk_val = clk_get_rate(clk_ctx->bitclk);
+ set_clk_val = dpu->bitclk;
+ if(clk_val != set_clk_val){
+ clk_val = clk_round_rate(clk_ctx->bitclk, set_clk_val);
+ clk_set_rate(clk_ctx->bitclk, clk_val);
+ DRM_DEBUG("set bitclk=%lld\n", clk_val);
+ }
+
+ clk_val = clk_get_rate(clk_ctx->pxclk);
+ DRM_DEBUG("get pxclk=%lld\n", clk_val);
+ clk_val = clk_get_rate(clk_ctx->mclk);
+ DRM_DEBUG("get mclk=%lld\n", clk_val);
+ clk_val = clk_get_rate(clk_ctx->hclk);
+ DRM_DEBUG("get hclk=%lld\n", clk_val);
+ clk_val = clk_get_rate(clk_ctx->escclk);
+ DRM_DEBUG("get escclk=%lld\n", clk_val);
+ clk_val = clk_get_rate(clk_ctx->bitclk);
+ DRM_DEBUG("get bitclk=%lld\n", clk_val);
+
+ udelay(10);
+ }
+
+ trace_dpu_enable_clocks(dpu->dev_id);
+
+ return 0;
+}
+
+static int dpu_disable_clocks(struct spacemit_dpu *dpu)
+{
+ struct dpu_clk_context *clk_ctx = &dpu->clk_ctx;
+ struct spacemit_drm_private *priv;
+ struct spacemit_hw_device *hwdev;
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ trace_dpu_disable_clocks(dpu->dev_id);
+
+ if (dpu->logo_booton) {
+ dpu_finish_uboot(dpu);
+ if (dpu->type == HDMI) {
+ clk_disable_unprepare(clk_ctx->hmclk);
+ } else if (dpu->type == DSI) {
+ clk_disable_unprepare(clk_ctx->pxclk);
+ clk_disable_unprepare(clk_ctx->mclk);
+ clk_disable_unprepare(clk_ctx->hclk);
+ clk_disable_unprepare(clk_ctx->escclk);
+ clk_disable_unprepare(clk_ctx->bitclk);
+ }
+ return 0;
+ }
+
+ priv = dpu->crtc.dev->dev_private;
+ hwdev = priv->hwdev;
+
+ if (hwdev->is_hdmi) {
+ clk_disable_unprepare(clk_ctx->hmclk);
+ } else {
+ clk_disable_unprepare(clk_ctx->pxclk);
+ clk_disable_unprepare(clk_ctx->mclk);
+ clk_disable_unprepare(clk_ctx->hclk);
+ clk_disable_unprepare(clk_ctx->escclk);
+ clk_disable_unprepare(clk_ctx->bitclk);
+ }
+
+ return 0;
+}
+
+u8 spacemit_plane_hw_get_format_id(u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(primary_fmts); i++) {
+ if (primary_fmts[i].format == format)
+ return primary_fmts[i].id;
+ }
+
+ return SPACEMIT_DPU_INVALID_FORMAT_ID;
+}
+
+static bool parsr_afbc_modifier(uint64_t modifier, uint8_t* tile_type, uint8_t* block_size, uint8_t* yuv_transform, uint8_t* split_mode)
+{
+ uint64_t super_block_size = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
+
+ if (block_size && (super_block_size == AFBC_FORMAT_MOD_BLOCK_SIZE_16x16)) {
+ *block_size = 0;
+ } else if (block_size && (super_block_size == AFBC_FORMAT_MOD_BLOCK_SIZE_32x8)) {
+ *block_size = 1;
+ } else {
+ DRM_ERROR("unsupport modifier = 0x%llu, super_block_size = 0x%llu, dpu support only 16x16 and 32x8!\n", modifier, super_block_size);
+ return false;
+ }
+
+ if (tile_type && (modifier & AFBC_FORMAT_MOD_TILED)) {
+ *tile_type = 1;
+ }
+
+ if (yuv_transform && (modifier & AFBC_FORMAT_MOD_YTR)) {
+ *yuv_transform = 1;
+ }
+
+ if (split_mode && (modifier & AFBC_FORMAT_MOD_SPLIT)) {
+ *split_mode = 1;
+ }
+
+ return true;
+}
+
+void spacemit_update_csc_matrix(struct drm_plane *plane, struct drm_plane_state *old_state){
+ struct spacemit_plane_state *spacemit_plane_state = to_spacemit_plane_state(plane->state);
+ u32 rdma_id = spacemit_plane_state->rdma_id;
+ u32 module_base;
+ int color_encoding = plane->state->color_encoding;
+ int color_range = plane->state->color_range;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ int value;
+
+ module_base = RDMA0_BASE_ADDR + rdma_id * RDMA_SIZE;
+
+ if ((color_encoding != old_state->color_encoding) || (color_range != old_state->color_range)){
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][0] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][1] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX0, value);
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][2] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][3] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX1, value);
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][4] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][5] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX2, value);
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][6] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][7] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX3, value);
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][8] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][9] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX4, value);
+ value = (spacemit_yuv2rgb_coefs[color_encoding][color_range][10] & 0x3FFF) | ((spacemit_yuv2rgb_coefs[color_encoding][color_range][11] & 0x3FFF) << 14);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, CSC_MATRIX5, value);
+ }
+}
+
+static void saturn_conf_scaler_x(struct drm_plane_state *state)
+{
+ struct spacemit_plane_state *spacemit_plane_state = to_spacemit_plane_state(state);
+ struct drm_plane *plane = state->plane;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ u32 in_width, in_height, out_width, out_height;
+ uint32_t hor_delta_phase, ver_delta_phase;
+ int64_t hor_init_phase, ver_init_phase;
+ u32 module_base;
+
+ trace_saturn_conf_scaler_x(spacemit_plane_state);
+
+ /* should never happen */
+ if (unlikely(spacemit_plane_state->scaler_id >= MAX_SCALER_NUMS))
+ panic("Invalid scaler id:%d\n", spacemit_plane_state->scaler_id);
+
+ if (state->rotation == DRM_MODE_ROTATE_90 || state->rotation == DRM_MODE_ROTATE_270) {
+ in_width = state->src_h >> 16;
+ in_height = state->src_w >> 16;
+ } else {
+ in_width = state->src_w >> 16;
+ in_height = state->src_h >> 16;
+ }
+
+ out_width = state->crtc_w;
+ out_height = state->crtc_h;
+
+ /* Config SCALER scaling regs */
+ module_base = SCALER0_ONLINE_BASE_ADDR + spacemit_plane_state->scaler_id * SCALER_SIZE;
+
+ hor_delta_phase = in_width * 65536 / out_width;
+ ver_delta_phase = in_height * 65536 / out_height;
+
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_7, hor_delta_phase); //0x10000
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_8, ver_delta_phase); //0x5555
+
+ //TODO: start cor
+ hor_init_phase = ((int64_t)hor_delta_phase - 65536) >> 1;
+ ver_init_phase = ((int64_t)ver_delta_phase - 65536) >> 1;
+
+ DRM_DEBUG("hor_delta:%d ver_delta:%d\n", hor_delta_phase, ver_delta_phase);
+ DRM_DEBUG("hor_init_phase:%lld ver_init_phase:%lld\n", hor_init_phase, ver_init_phase);
+
+ if (hor_init_phase >= 0) {
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_3, hor_init_phase & 0x00000000ffffffff); //0x0
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_4, 0);
+ } else { //convert to positive value if negative
+ hor_init_phase += 8589934592;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_3, hor_init_phase & 0x00000000ffffffff);
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_4, (hor_init_phase & 0x0000000100000000) >> 32);
+ }
+
+ if (ver_init_phase >= 0) {
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_5, ver_init_phase & 0x00000000ffffffff);
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_6, 0);
+ } else { //convert to positive value if negative
+ ver_init_phase += 8589934592;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_5, ver_init_phase & 0x00000000ffffffff);
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_6, (ver_init_phase & 0x0000000100000000) >> 32);
+ }
+
+ // enable both ver and hor
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_0, in_width << 8 | 0x1 << 1 | 0x1);
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_1, out_width << 16 | in_height);
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_2, out_height);
+
+ /* Config RDMA scaling regs */
+ module_base = RDMA0_BASE_ADDR + spacemit_plane_state->rdma_id * RDMA_SIZE;
+
+ ver_init_phase = ((int64_t)ver_delta_phase - 65536) / 2;
+ if (ver_init_phase >= 0) {
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_INIT_PHASE_V_LOW, ver_init_phase & 0x00000000ffffffff);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_INIT_PHASE_V_HIGH, 0); //TODO: only 1 bit, read then write??
+ } else { //convert to positive value if negative
+ ver_init_phase += 8589934592;
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_INIT_PHASE_V_LOW, ver_init_phase & 0x00000000ffffffff);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_INIT_PHASE_V_HIGH, (ver_init_phase & 0x0000000100000000) >> 32);
+ }
+
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_SCL_RATIO_V, 0x1 << 20 | ver_delta_phase);
+}
+
+void saturn_conf_scaler_coefs(struct drm_plane *plane, struct spacemit_plane_state *spacemit_pstate){
+ struct drm_property_blob * blob = spacemit_pstate->scale_coefs_blob_prop;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ int scale_num = 192;
+ u32 module_base;
+ int val;
+ int *coef_data;
+
+ /* should never happen */
+ if (unlikely(spacemit_pstate->scaler_id >= MAX_SCALER_NUMS))
+ DRM_ERROR("Invalid scaler id:%d\n", spacemit_pstate->scaler_id);
+
+ /* Config SCALER scaling regs */
+ module_base = SCALER0_ONLINE_BASE_ADDR + spacemit_pstate->scaler_id * SCALER_SIZE;
+
+ if (blob){
+ /* should never happen */
+ if (unlikely(blob->length != scale_num))
+ DRM_ERROR("The blob length %ld is not correct scale_num %d\n", blob->length, scale_num);
+
+ coef_data = (int *)blob->data;
+ if (unlikely(NULL == coef_data)){
+ DRM_ERROR("The coef data is NULL\n");
+ return;
+ }
+
+ val = (coef_data[0] & 0xFFFF) | coef_data[1] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_9, val);
+ val = (coef_data[2] & 0xFFFF) | coef_data[3] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_10, val);
+ val = (coef_data[4] & 0xFFFF) | coef_data[5] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_11, val);
+ val = (coef_data[6] & 0xFFFF) | coef_data[7] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_12, val);
+ val = (coef_data[8] & 0xFFFF) | coef_data[9] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_13, val);
+ val = (coef_data[10] & 0xFFFF) | coef_data[11] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_14, val);
+ val = (coef_data[12] & 0xFFFF) | coef_data[13] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_15, val);
+ val = (coef_data[14] & 0xFFFF) | coef_data[15] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_16, val);
+ val = (coef_data[16] & 0xFFFF) | coef_data[17] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_17, val);
+ val = (coef_data[18] & 0xFFFF) | coef_data[19] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_18, val);
+ val = (coef_data[20] & 0xFFFF) | coef_data[21] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_19, val);
+ val = (coef_data[22] & 0xFFFF) | coef_data[23] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_20, val);
+ val = (coef_data[24] & 0xFFFF) | coef_data[25] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_21, val);
+ val = (coef_data[26] & 0xFFFF) | coef_data[27] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_22, val);
+ val = (coef_data[28] & 0xFFFF) | coef_data[29] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_23, val);
+ val = (coef_data[30] & 0xFFFF) | coef_data[31] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_24, val);
+ val = (coef_data[32] & 0xFFFF) | coef_data[33] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_25, val);
+ val = (coef_data[34] & 0xFFFF) | coef_data[35] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_26, val);
+ val = (coef_data[36] & 0xFFFF) | coef_data[37] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_27, val);
+ val = (coef_data[38] & 0xFFFF) | coef_data[39] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_28, val);
+ val = (coef_data[40] & 0xFFFF) | coef_data[41] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_29, val);
+ val = (coef_data[42] & 0xFFFF) | coef_data[43] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_30, val);
+ val = (coef_data[44] & 0xFFFF) | coef_data[45] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_31, val);
+ val = (coef_data[46] & 0xFFFF) | coef_data[47] << 16;
+ write_to_cmdlist(priv, SCALER_X_REG, module_base, disp_scl_reg_32, val);
+ }
+}
+
+static void spacemit_set_afbc_info(struct spacemit_drm_private *priv, uint64_t modifier, u32 module_base)
+{
+ bool ret = false;
+ u8 tile_type = 0;
+ u8 block_size = 0;
+ u8 yuv_transform = 0;
+ u8 split_mode = 0;
+
+ ret = parsr_afbc_modifier(modifier, &tile_type, &block_size, &yuv_transform, &split_mode);
+ if (!ret) {
+ DRM_ERROR("Faild to set afbc plane\n");
+ return;
+ }
+
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, AFBC_CFG, tile_type << 3 | block_size << 2 | yuv_transform << 1 | split_mode);
+
+ return;
+}
+
+#define CONFIG_HW_COMPOSER_LAYER(id) \
+{\
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _rect_ltopx, crtc_x); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _rect_ltopy, crtc_y); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _rect_rbotx, crtc_x + crtc_w - 1); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _rect_rboty, crtc_y + crtc_h - 1); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _color_key_en, 0); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _blend_mode, blend_mode); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _alpha_sel, alpha_sel); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _layer_alpha, alpha); \
+ if (unlikely(solid_en)) { \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_color_R, solid_r); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_color_G, solid_g); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_color_B, solid_b); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_color_A, solid_a); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_en, 1); \
+ DRM_DEBUG("solid_r:0x%x, solid_g:0x%x, solid_b:0x%x, solid_a:0x%x\n", \
+ solid_r, solid_g, solid_b, solid_a); \
+ } else { \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _solid_en, 0); \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _layer_id, rdma_id); \
+ } \
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl ## id ## _en, 1); \
+}
+
+void spacemit_plane_update_hw_channel(struct drm_plane *plane)
+{
+ struct drm_plane_state *state = plane->state;
+ struct spacemit_plane *spacemit_plane = to_spacemit_plane(plane);
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct spacemit_plane_state *spacemit_plane_state = to_spacemit_plane_state(state);
+ u32 rdma_id = spacemit_plane_state->rdma_id;
+ u8 alpha = state->alpha >> 8;
+ u16 pixel_alpha = state->pixel_blend_mode;
+ u32 src_w, src_h, src_x, src_y;
+ u32 crtc_w, crtc_h, crtc_x, crtc_y;
+ u32 alpha_sel, blend_mode = 0;
+ u8 uv_swap = 0;
+ uint32_t fccf = fb->format->format;
+ u32 module_base, base;
+ u32 val;
+ bool solid_en = false;
+ u32 solid_a, solid_r, solid_g, solid_b;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ bool is_afbc = (fb->modifier > 0);
+ u8 channel = crtc_to_dpu(state->crtc)->dev_id;
+
+ trace_spacemit_plane_update_hw_channel("rdma_id", rdma_id);
+
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+ src_x = state->src_x >> 16;
+ src_y = state->src_y >> 16;
+
+ crtc_w = state->crtc_w;
+ crtc_h = state->crtc_h;
+ crtc_x = state->crtc_x;
+ crtc_y = state->crtc_y;
+
+ if (rdma_id == RDMA_INVALID_ID)
+ solid_en = true;
+
+ spacemit_plane_state->is_offline = 0;
+
+ trace_dpu_plane_info(state, fb, rdma_id, alpha,
+ state->rotation, is_afbc);
+
+ /* For solid color both src_w and src_h are 0 */
+ if (solid_en == false) {
+ /* Set RDMA regs */
+ module_base = RDMA0_BASE_ADDR + rdma_id * RDMA_SIZE;
+ val = 0x0 << 26 | 0x0 << 25 | 0xf << 17 | 0x0 << 15 | channel << 12 | 0x0 << 7 | 0xf << 2 | (is_afbc ? 1 : 0);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LAYER_CTRL, val);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, COMPSR_Y_OFST, crtc_y);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_SCL_RATIO_V, 0x0 << 20);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_IMG_SIZE, fb->height << 16 | fb->width);
+ val = src_y + src_h;
+
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_CROP_POS_START, src_y << 16 | src_x);
+ val = ((val - 1) << 16) | (src_x + src_w - 1);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_CROP_POS_END, val);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_ALPHA01, 0x0 << 16 | 0x0);
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, LEFT_ALPHA23, 0x0 << 16 | 0x0);
+
+ saturn_write_fbcmem_regs(state, rdma_id, module_base, NULL);
+
+ val = 0;
+ /* setup the rotation and axis flip bits */
+ if (state->rotation & DRM_MODE_ROTATE_MASK)
+ val = ilog2(plane->state->rotation & DRM_MODE_ROTATE_MASK) & 0x3;
+ if (state->rotation & DRM_MODE_REFLECT_MASK)
+ val = ilog2(plane->state->rotation & DRM_MODE_REFLECT_MASK);
+
+ if (fccf == DRM_FORMAT_YVYU || fccf == DRM_FORMAT_VYUY || fccf == DRM_FORMAT_NV21 || fccf == DRM_FORMAT_YVU420 || fccf == DRM_FORMAT_Q401) {
+ uv_swap = 1;
+ }
+
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, ROT_MODE, val << 7 | uv_swap << 6 | spacemit_plane_state->format);
+
+ if (fb->modifier) {
+ spacemit_set_afbc_info(priv, fb->modifier, module_base);
+ }
+
+ if (spacemit_plane_state->use_scl){
+ saturn_conf_scaler_x(state);
+
+ /*scaling mismatch gpu render result without these coefs*/
+ saturn_conf_scaler_coefs(plane, spacemit_plane_state);
+ }
+ } else {
+ solid_r = (u8)spacemit_plane_state->solid_color;
+ solid_g = (u8)(spacemit_plane_state->solid_color >> 8);
+ solid_b = (u8)(spacemit_plane_state->solid_color >> 16);
+ solid_a = (u8)(spacemit_plane_state->solid_color >> 24);
+ solid_r = solid_r << hwdev->solid_color_shift;
+ solid_g = solid_g << hwdev->solid_color_shift;
+ solid_b = solid_b << hwdev->solid_color_shift;
+ }
+
+ /* Set layer regs */
+ if (state->fb->format->has_alpha)
+ alpha_sel = 0x1;
+ else
+ alpha_sel = 0x0;
+
+ switch (pixel_alpha) {
+ case DRM_MODE_BLEND_PIXEL_NONE:
+ /* k1x supports knone + layer alpha*/
+ alpha_sel = 0x0;
+ fallthrough;
+ case DRM_MODE_BLEND_COVERAGE:
+ blend_mode = 0x0;
+ break;
+ case DRM_MODE_BLEND_PREMULTI:
+ blend_mode = 0x1;
+ break;
+ default:
+ DRM_ERROR("Unsupported blend mode!\n");
+ }
+
+ /* enable composer and bind RDMA */
+ base = CMP_BASE_ADDR(channel);
+ switch(spacemit_plane->hw_pid) {
+ case 0:
+ CONFIG_HW_COMPOSER_LAYER(0);
+ break;
+ case 1:
+ CONFIG_HW_COMPOSER_LAYER(1);
+ break;
+ case 2:
+ CONFIG_HW_COMPOSER_LAYER(2);
+ break;
+ case 3:
+ CONFIG_HW_COMPOSER_LAYER(3);
+ break;
+ case 4:
+ CONFIG_HW_COMPOSER_LAYER(4);
+ break;
+ case 5:
+ CONFIG_HW_COMPOSER_LAYER(5);
+ break;
+ case 6:
+ CONFIG_HW_COMPOSER_LAYER(6);
+ break;
+ case 7:
+ CONFIG_HW_COMPOSER_LAYER(7);
+ break;
+ default:
+ DRM_ERROR("%s unsupported zpos:%d\n", __func__, state->zpos);
+ break;
+ }
+}
+
+void spacemit_plane_disable_hw_channel(struct drm_plane *plane, struct drm_plane_state *old_state)
+{
+ struct spacemit_plane *p = to_spacemit_plane(plane);
+ u8 channel = crtc_to_dpu(old_state->crtc)->dev_id;
+ u32 base = CMP_BASE_ADDR(channel);
+ u32 rdma_id = to_spacemit_plane_state(old_state)->rdma_id;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ DRM_DEBUG("%s() layer_id = %u rdma_id:%d\n", __func__, p->hw_pid, rdma_id);
+
+ trace_spacemit_plane_disable_hw_channel(p->hw_pid, rdma_id);
+
+ switch (p->hw_pid) {
+ case 0:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl0_en, 0);
+ break;
+ case 1:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl1_en, 0);
+ break;
+ case 2:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl2_en, 0);
+ break;
+ case 3:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl3_en, 0);
+ break;
+ case 4:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl4_en, 0);
+ break;
+ case 5:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl5_en, 0);
+ break;
+ case 6:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl6_en, 0);
+ break;
+ case 7:
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nl7_en, 0);
+ break;
+ default:
+ DRM_ERROR("%s unsupported zpos:%d\n", __func__, old_state->zpos);
+ break;
+ }
+}
+
+static u32 saturn_conf_dpuctrl_scaling(struct spacemit_dpu *dpu)
+{
+ struct spacemit_dpu_scaler *scaler = NULL;
+ struct spacemit_crtc_state *ac = to_spacemit_crtc_state(dpu->crtc.state);
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u32 scl_en = 0;
+ u32 i;
+
+ for (i = 0; i < MAX_SCALER_NUMS; i++) {
+ scaler = &(ac->scalers[i]);
+ DRM_DEBUG("scaler%d: in_use:0x%x rdma_id:%d\n", i, scaler->in_use, scaler->rdma_id);
+ trace_dpuctrl_scaling_setting(i, scaler->in_use, scaler->rdma_id);
+ if (scaler->in_use) {
+ scl_en |= (i + 1);
+ //TODO: expand below code when more than 2 sclaers
+ if (i == 0)
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl_nml_scl0_layer_id, scaler->rdma_id);
+ if (i == 1)
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl_nml_scl1_layer_id, scaler->rdma_id);
+ }
+ }
+
+ DRM_DEBUG("scl_en:%d\n", scl_en);
+ trace_dpuctrl_scaling("scl_en", scl_en);
+ return scl_en;
+}
+
+void spacemit_update_hdr_matrix(struct drm_plane *plane, struct spacemit_plane_state *spacemit_pstate){
+
+}
+
+static u32 saturn_conf_dpuctrl_rdma(struct spacemit_dpu *dpu)
+{
+ struct drm_crtc *crtc = &dpu->crtc;
+ struct drm_plane *plane;
+ u32 rdma_en = 0;
+
+ /* Find out the active rdmas */
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ u32 rdma_id = to_spacemit_plane_state(plane->state)->rdma_id;
+
+ if (rdma_id != RDMA_INVALID_ID)
+ rdma_en |= (1 << rdma_id);
+ }
+
+ trace_dpuctrl("rdma_en", rdma_en);
+
+ return rdma_en;
+}
+
+void saturn_conf_dpuctrl_color_matrix(struct spacemit_dpu *dpu, struct drm_crtc_state *old_state)
+{
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ struct drm_crtc_state *state = dpu->crtc.state;
+ struct spacemit_crtc_state *spacemit_state = to_spacemit_crtc_state(state);
+ struct drm_property_blob * blob = spacemit_state->color_matrix_blob_prop;
+ int *color_matrix;
+
+ /*For color matrix, if no update from user space,
+ we keep the original configuration, do not change the value of any color matix register*/
+ if (blob){
+ color_matrix = (int*)blob->data;
+
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_npost_proc_en, 1);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_nendmatrix_en, 1);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_ngain_to_full_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_nmatrix_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_nfront_tmootf_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_nend_tmootf_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_neotf_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_noetf_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table0, color_matrix[0]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table1, color_matrix[1]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table2, color_matrix[2]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table3, color_matrix[3]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table4, color_matrix[4]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table5, color_matrix[5]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table6, color_matrix[6]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table7, color_matrix[7]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_table8, color_matrix[8]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_offset0, color_matrix[9]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_offset1, color_matrix[10]);
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_pendmatrix_offset2, color_matrix[11]);
+ }
+
+ return;
+}
+
+static void saturn_conf_dpuctrl(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ u32 scl_en = 0;
+ u32 rdma_en = 0;
+ u32 base = DPU_CTRL_BASE_ADDR;
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ rdma_en = saturn_conf_dpuctrl_rdma(dpu);
+ scl_en = saturn_conf_dpuctrl_scaling(dpu);
+
+ cmdlist_sort_by_group(crtc);
+ cmdlist_atomic_commit(crtc, old_state);
+
+ switch (dpu->dev_id) {
+ case ONLINE2:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl2_nml_scl_en, scl_en);
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl2_nml_rch_en, rdma_en);
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl2_nml_outctl_en, 0x1);
+ break;
+ case OFFLINE0:
+ /* TODO */
+ break;
+ default:
+ DRM_ERROR("%s, dpu_id %d is invalid!\n", __func__, dpu->dev_id);
+ break;
+ }
+}
+
+static void saturn_irq_enable(struct spacemit_dpu *dpu, bool enable)
+{
+ u32 base = DPU_INT_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ trace_saturn_irq_enable("irq", enable);
+
+ if (dpu->dev_id == ONLINE2) {
+ /* enable online2 irq */
+ dpu_write_reg(hwdev, DPU_INTP_REG, base, b.onl2_nml_frm_timing_eof_int_msk, enable ? 1 : 0);
+ dpu_write_reg(hwdev, DPU_INTP_REG, base, b.onl2_nml_cfg_rdy_clr_int_msk, enable ? 1 : 0);
+ dpu_write_reg(hwdev, DPU_INTP_REG, base, b.onl2_nml_frm_timing_unflow_int_msk, enable ? 1 : 0);
+ dpu_write_reg(hwdev, DPU_INTP_REG, base, b.onl2_nml_cmdlist_ch_frm_cfg_done_int_msk, enable ? 0xF : 0);
+ }
+}
+
+static void saturn_enable_vsync(struct spacemit_dpu *dpu, bool enable)
+{
+ u32 base = DPU_INT_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ trace_saturn_enable_vsync("vsync", enable);
+ if (dpu->dev_id == ONLINE2)
+ dpu_write_reg(hwdev, DPU_INTP_REG, base, b.onl2_nml_frm_timing_vsync_int_msk, enable ? 1 : 0);
+}
+
+static void saturn_ctrl_cfg_ready(struct spacemit_dpu *dpu, bool enable)
+{
+ u32 base = DPU_CTRL_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ trace_saturn_ctrl_cfg_ready(dpu->dev_id, enable);
+
+ switch (dpu->dev_id) {
+ case ONLINE0:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl0_nml_cfg_rdy, enable ? 1 : 0);
+ break;
+ case ONLINE1:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl1_nml_cfg_rdy, enable ? 1 : 0);
+ break;
+ case ONLINE2:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl2_nml_cfg_rdy, enable ? 1 : 0);
+ break;
+ case OFFLINE0:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl3_nml_cfg_rdy, enable ? 1 : 0);
+ break;
+ case OFFLINE1:
+ dpu_write_reg(hwdev, DPU_CTL_REG, base, ctl4_nml_cfg_rdy, enable ? 1 : 0);
+ break;
+ default:
+ DRM_ERROR("id is invalid!\n");
+ break;
+ }
+}
+
+static void saturn_ctrl_sw_start(struct spacemit_dpu *dpu, bool enable)
+{
+ u32 base = DPU_CTRL_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ trace_saturn_ctrl_sw_start(dpu->dev_id, enable);
+
+ switch (dpu->dev_id) {
+ case ONLINE0:
+ dpu_write_reg_w1c(hwdev, DPU_CTL_REG, base, ctl0_sw_start, enable ? 1 : 0);
+ break;
+ case ONLINE1:
+ dpu_write_reg_w1c(hwdev, DPU_CTL_REG, base, ctl1_sw_start, enable ? 1 : 0);
+ break;
+ case ONLINE2:
+ dpu_write_reg_w1c(hwdev, DPU_CTL_REG, base, ctl2_sw_start, enable ? 1 : 0);
+ break;
+ case OFFLINE0:
+ dpu_write_reg_w1c(hwdev, DPU_CTL_REG, base, ctl3_sw_start, enable ? 1 : 0);
+ break;
+ default:
+ DRM_ERROR("id is invalid!\n");
+ break;
+ }
+}
+
+void saturn_wb_disable(struct spacemit_dpu *dpu)
+{
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_nml_wb_en, 0);
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_nml_cfg_rdy, 1);
+}
+
+void saturn_wb_config(struct spacemit_dpu *dpu)
+{
+
+}
+
+static u32 dpu_get_version(struct spacemit_dpu *dpu)
+{
+ return 0;
+}
+
+static void saturn_init_csc(struct spacemit_dpu *dpu){
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u32 module_base;
+ int i = 0;
+
+ for(i = 0; i < hwdev->rdma_nums; i++){
+ module_base = RDMA0_BASE_ADDR + i * RDMA_SIZE;
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix00, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][0] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix01, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][1] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix02, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][2] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix03, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][3] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix10, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][4] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix11, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][5] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix12, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][6] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix13, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][7] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix20, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][8] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix21, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][9] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix22, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][10] & 0x3FFF);
+ dpu_write_reg(hwdev, RDMA_PATH_X_REG, module_base, b.csc_matrix23, spacemit_yuv2rgb_coefs[DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE][11] & 0x3FFF);
+ }
+}
+
+static void saturn_init_regs(struct spacemit_dpu *dpu)
+{
+ u32 base = 0;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ struct drm_crtc *crtc = &dpu->crtc;
+ struct drm_display_mode *mode = &crtc->mode;
+ u8 channel = dpu->dev_id;
+ u16 vfp, vbp, vsync, hfp, hbp, hsync;
+ // u32 value;
+
+ hsync = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
+ hfp = mode->hsync_start - mode->hdisplay;
+ vsync = mode->vsync_end - mode->vsync_start;
+ vbp = mode->vtotal - mode->vsync_end;
+ vfp = mode->vsync_start - mode->vdisplay;
+ trace_drm_display_mode_info(mode);
+
+ base = CMP_BASE_ADDR(channel);
+ /* set bg color to black */
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nbg_color_B, 0x0);
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nbg_color_R, 0x0);
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nbg_color_G, 0xFF);
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_nbg_color_A, 0xFF);
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_ncmps_en, 1);
+
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_noutput_width, mode->hdisplay);
+ dpu_write_reg(hwdev, CMPS_X_REG, base, m_noutput_height, mode->vdisplay);
+
+ base = OUTCTRL_BASE_ADDR(channel);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, m_n_inheight, mode->vdisplay);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, m_n_inwdith, mode->hdisplay);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, scale_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, dither_en, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, sbs_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, split_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, narrow_yuv_en, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, cmd_screen, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, frame_timing_en, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, split_overlap, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, hblank, 0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, back_ground_r, 0xfff);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, back_ground_g, 0x0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, back_ground_b, 0x0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, sof_pre_ln_num, 0x0);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, cfg_ln_num_intp, 0x0);
+
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, hbp, hbp);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, hfp, hfp);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, vfp, vfp);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, vbp, vbp);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, hsync_width, hsync);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, hsp, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, vsync_width, vsync);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, vsp, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, h_active, mode->hdisplay);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, v_active, mode->vdisplay);
+
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, user, 2); /* RGB888 */
+
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, eof_ln_dly, 16);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, eof0_irq_mask, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, underflow0_irq_mask, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, eof1_irq_mask, 1);
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, underflow1_irq_mask, 1);
+
+ // if (hwdev->is_hdmi) {
+ // dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, base, disp_ready_man_en, 1);
+ // value = dpu_read_reg(hwdev, OUTCTRL_TOP_X_REG, base, value32[31]);
+ // DRM_INFO("%s read OUTCTRL_TOP_X_REG value32[31] 0x%x", __func__, value);
+ // }
+
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_video_mod, 0x1);
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_dbg_mod, 0x0);
+ /*
+ * ctl2_timing_inter0 use default value
+ * ctl2_timing_inter1 = 2 * ⌈fmclk / fdscclk⌉, set 0xf as max value
+ */
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_timing_inter1, DPU_CTRL_MAX_TIMING_INTER1);
+
+ dpu_write_reg(hwdev, MMU_REG, MMU_BASE_ADDR, b.cfg_dmac0_rd_outs_num, 16);
+ dpu_write_reg(hwdev, MMU_REG, MMU_BASE_ADDR, b.cfg_dmac0_axi_burst, 1);
+
+ /* totally disable post proc */
+ dpu_write_reg(hwdev, OUTCTRL_PROC_X_REG, PP2_BASE_ADDR, m_npost_proc_en, 0);
+}
+
+static void saturn_setup_dma_top(struct spacemit_dpu *dpu)
+{
+ u32 base = DMA_TOP_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, img_rr_ratio, 0x10);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, round_robin_mode, 0);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, pixel_num_th, 4);
+
+ //regnum: 2, offset: 0x08
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, rdma_timeout_limit, 0xFFFE);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, wdma_timeout_limit, 0xFFFF);
+
+ //regnum: 7, offset: 0x1C
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, online_rqos, DPU_QOS_NORMAL);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, offline_rqos, DPU_QOS_LOW);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, online_wqos, DPU_QOS_LOW);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, offline_wqos, DPU_QOS_LOW);
+
+ //regnum: 17, offset: 0x44
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, cmdlist_rqos, 4);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, dmac0_burst_length, 1);
+
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, dmac0_rd_outs_num, 8);
+ dpu_write_reg(hwdev, DMA_TOP_REG, base, dmac0_wr_outs_num, 16);
+
+ if (dpu_read_reg(hwdev, DMA_TOP_REG, base, cmdlist_rqos) < DPU_QOS_URGENT || \
+ dpu_read_reg(hwdev, DMA_TOP_REG, base, online_rqos) < dpu_read_reg(hwdev, DMA_TOP_REG, base, offline_rqos)) {
+ // panic("dma_top qos cfg failed!\n");
+ }
+}
+
+
+static void saturn_setup_mmu_top(struct spacemit_dpu *dpu)
+{
+ unsigned int val;
+ unsigned int rd_outs_num = 0;
+ u32 base = MMU_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ rd_outs_num = RD_OUTS_NUM / 2;
+
+ /* MMU TOP init setting */
+ dpu_write_reg(hwdev, MMU_REG, base, v.TBU_Timelimit, (0x1 << 16) | RDMA_TIMELIMIT);
+ dpu_write_reg(hwdev, MMU_REG, base, v.TBU_AXI_PORT_SEL, 0);
+
+ val = dpu_read_reg(hwdev, MMU_REG, base, v.MMU_Dmac0_Reg);
+ val &= ~(0xFF << 16);
+ val |= (rd_outs_num << 16);
+ dpu_write_reg(hwdev, MMU_REG, base, v.MMU_Dmac0_Reg, val);
+
+ val = dpu_read_reg(hwdev, MMU_REG, base, v.MMU_Dmac1_Reg);
+ val &= ~(0xFF << 16);
+ val |= (rd_outs_num << 16);
+ dpu_write_reg(hwdev, MMU_REG, base, v.MMU_Dmac1_Reg, val);
+
+ val = dpu_read_reg(hwdev, MMU_REG, base, v.MMU_Dmac2_Reg);
+ val &= ~(0xFF << 16);
+ val |= (rd_outs_num << 16);
+ dpu_write_reg(hwdev, MMU_REG, base, v.MMU_Dmac2_Reg, val);
+
+ val = dpu_read_reg(hwdev, MMU_REG, base, v.MMU_Dmac3_Reg);
+ val &= ~(0xFF << 16);
+ val |= (rd_outs_num << 16);
+ dpu_write_reg(hwdev, MMU_REG, base, v.MMU_Dmac3_Reg, val);
+}
+
+static int dpu_init(struct spacemit_dpu *dpu)
+{
+ unsigned int timeout = 1000;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+#ifdef CONFIG_SPACEMIT_FPGA
+ void __iomem *addr = (void __iomem *)ioremap(0xD4282800, 100);
+#endif
+ void __iomem *ciu_addr = (void __iomem *)ioremap(0xD4282C00, 0x200);
+ u32 value;
+
+ DRM_INFO("%s \n", __func__);
+ trace_dpu_init(dpu->dev_id);
+
+ while(timeout) {
+ if (dpu_read_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, value32[27]) == 0)
+ break;
+ udelay(100);
+ timeout--;
+ };
+ if (timeout == 0)
+ DRM_ERROR("%s wait cfg ready done timeout\n", __func__);
+
+#ifdef CONFIG_SPACEMIT_FPGA
+ // for FPGA: enable PMU
+ writel(0xffa1ffff, addr + 0x44);
+ writel(0xFF65FF05, addr + 0x4c);
+#endif
+
+ // modified hdmi and mipi dsi qos
+ value = readl_relaxed(ciu_addr + 0x011c);
+ DRM_DEBUG("%s ciu offset 0x011c:0x%x\n", __func__, value);
+ value = readl_relaxed(ciu_addr + 0x0124);
+ DRM_DEBUG("%s ciu offset 0x0124:0x%x\n", __func__, value);
+ writel(value | 0xffff, ciu_addr + 0x0124);
+ udelay(2);
+ value = readl_relaxed(ciu_addr + 0x0124);
+ DRM_DEBUG("%s ciu offset 0x0124:0x%x\n", __func__, value);
+
+ saturn_init_regs(dpu);
+ saturn_setup_dma_top(dpu);
+ saturn_setup_mmu_top(dpu);
+ saturn_irq_enable(dpu, true);
+ saturn_init_csc(dpu);
+
+ return 0;
+}
+
+static void dpu_uninit(struct spacemit_dpu *dpu)
+{
+ trace_dpu_uninit(dpu->dev_id);
+ saturn_irq_enable(dpu, false);
+}
+
+static uint32_t dpu_isr(struct spacemit_dpu *dpu)
+{
+ uint32_t irq_raw, int_mask = 0;
+ u32 base = DPU_INT_BASE_ADDR;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ static bool flip_done[DP_MAX_DEVICES] = {false};
+ struct drm_writeback_connector *wb_conn = &dpu->wb_connector;
+ u8 channel = dpu->dev_id;
+ int flip_id;
+
+ if (hwdev->is_hdmi) {
+ flip_id = SATURN_HDMI;
+ } else {
+ flip_id = SATURN_LE;
+ }
+
+ trace_dpu_isr(dpu->dev_id);
+
+ if (dpu->dev_id == ONLINE2) {
+ irq_raw = dpu_read_reg(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_24);
+ trace_dpu_isr_status("ONLINE2", irq_raw );
+ /* underrun */
+ if (irq_raw & DPU_INT_FRM_TIMING_UNFLOW) {
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_INT_FRM_TIMING_UNFLOW);
+ trace_dpu_isr_status("Under Run!", irq_raw & DPU_INT_FRM_TIMING_UNFLOW);
+ trace_dpu_isr_ul_data("DPU Mclk", dpu->cur_mclk);
+ trace_dpu_isr_ul_data("DPU BW", dpu->cur_bw);
+ dpu_dump_reg(dpu);
+ queue_work(dpu->dpu_underrun_wq, &dpu->work_stop_trace);
+ DRM_ERROR_RATELIMITED("Under Run! DPU_Mclk = %ld, DPU BW = %ld\n", (unsigned long)dpu->cur_mclk, (unsigned long)dpu->cur_bw);
+ int_mask |= DPU_INT_UNDERRUN;
+ }
+ /* eof */
+ if (irq_raw & DPU_INT_FRM_TIMING_EOF) {
+ dpu_write_reg_w1c(hwdev, OUTCTRL_TOP_X_REG, OUTCTRL_BASE_ADDR(channel), eof0_irq_status, 1);
+ dpu_write_reg_w1c(hwdev, OUTCTRL_TOP_X_REG, OUTCTRL_BASE_ADDR(channel), eof1_irq_status, 1);
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_INT_FRM_TIMING_EOF);
+ trace_dpu_isr_status("eof", irq_raw & DPU_INT_FRM_TIMING_EOF);
+ }
+ /* cfg ready clear */
+ if (irq_raw & DPU_INT_CFG_RDY_CLR) {
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_INT_CFG_RDY_CLR);
+ trace_dpu_isr_status("cfg_rdy_clr", irq_raw & DPU_INT_CFG_RDY_CLR);
+ flip_done[flip_id] = false;
+
+ trace_u64_data("irq crtc mclk cur", dpu->cur_mclk);
+ trace_u64_data("irq crtc mclk new", dpu->new_mclk);
+ trace_u64_data("irq crtc bw cur", dpu->cur_bw);
+ trace_u64_data("irq crtc bw new", dpu->new_bw);
+ if (dpu->enable_auto_fc && dpu->new_mclk < dpu->cur_mclk) {
+ trace_u64_data("run wq to set mclk", dpu->new_mclk);
+ queue_work(system_wq, &dpu->work_update_clk);
+ }
+ if (dpu->enable_auto_fc && dpu->new_bw < dpu->cur_bw) {
+ trace_u64_data("run wq to set bw", dpu->new_bw);
+ queue_work(system_wq, &dpu->work_update_bw);
+ }
+ }
+ /* vsync */
+ if (irq_raw & DPU_INT_FRM_TIMING_VSYNC) {
+ struct drm_crtc *crtc = &dpu->crtc;
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_INT_FRM_TIMING_VSYNC);
+ trace_u64_data("dpu name", (u64)hwdev->is_hdmi);
+ trace_dpu_isr_status("vsync", irq_raw & DPU_INT_FRM_TIMING_VSYNC);
+ drm_crtc_handle_vblank(crtc);
+
+ if (!flip_done[flip_id]) {
+ struct drm_device *drm = dpu->crtc.dev;
+ struct drm_pending_vblank_event *event = crtc->state->event;
+
+ flip_done[flip_id] = true;
+
+ spin_lock(&drm->event_lock);
+ if (crtc->state->event) {
+ /*
+ * Set event to NULL first to ensure event is consumed
+ * before drm_atomic_helper_commit_hw_done.
+ */
+ crtc->state->event = NULL;
+ drm_crtc_send_vblank_event(crtc, event);
+ }
+ spin_unlock(&drm->event_lock);
+ }
+ dpu_dump_fps(dpu);
+ }
+ /* wb done */
+ if (irq_raw & DPU_INT_WB_DONE) {
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, b.onl2_nml_wb_done_int_sts, irq_raw);
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_INT_WB_DONE);
+ saturn_wb_disable(dpu);
+ drm_writeback_signal_completion(wb_conn, 0);
+ }
+ /* rest irq status */
+ if (irq_raw & DPU_REST_INT_BITS)
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, v.dpu_int_reg_14, DPU_REST_INT_BITS);
+
+ }
+ if (dpu->dev_id == OFFLINE0) {
+ /*cfg ready*/
+ irq_raw = dpu_read_reg(hwdev, DPU_INTP_REG, base, b.offl0_cfg_rdy_clr_int_raw);
+ if (irq_raw)
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, b.offl0_cfg_rdy_clr_int_sts, 1);
+
+ /*wb*/
+ irq_raw = dpu_read_reg(hwdev, DPU_INTP_REG, base, b.offl0_wb_frm_done_int_raw);
+ if (irq_raw)
+ dpu_write_reg_w1c(hwdev, DPU_INTP_REG, base, b.offl0_wb_frm_done_int_sts, irq_raw);
+ }
+
+ return int_mask;
+}
+
+static void dpu_run(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ trace_dpu_run(dpu->dev_id);
+
+ /* config dpuctrl modules */
+ saturn_conf_dpuctrl(crtc, old_state);
+
+ //dsb(sy);
+ mb();
+ saturn_ctrl_cfg_ready(dpu, true);
+
+ if (unlikely(dpu->is_1st_f)) {
+ DRM_INFO("DPU type %d id %d Start!\n", dpu->type, dpu->dev_id);
+ dpu->is_1st_f = false;
+ saturn_ctrl_sw_start(dpu, true);
+ }
+
+#ifdef CONFIG_ARM64
+ __iomb();
+#else
+ dma_rmb();
+#endif
+}
+
+static void dpu_stop(struct spacemit_dpu *dpu)
+{
+ unsigned int timeout = DPU_STOP_TIMEOUT;
+ struct spacemit_drm_private *priv = dpu->crtc.dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u8 channel = dpu->dev_id;
+
+ flush_workqueue(dpu->dpu_underrun_wq);
+
+ trace_dpu_stop(dpu->dev_id);
+
+ while(timeout) {
+ if (dpu_read_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, value32[27]) == 0)
+ break;
+ udelay(10);
+ timeout--;
+ };
+ if (timeout == 0)
+ DRM_ERROR("%s wait cfg ready done timeout\n", __func__);
+ else
+ DRM_DEBUG("%s wait cfg ready done %d\n", __func__, timeout);
+
+ dpu_write_reg(hwdev, OUTCTRL_TOP_X_REG, OUTCTRL_BASE_ADDR(channel), value32[6], 0x0);
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_nml_rch_en, 0x0);
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, ctl2_nml_cfg_rdy, 0x1);
+
+ timeout = DPU_STOP_TIMEOUT;
+ while(timeout) {
+ if (dpu_read_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR, value32[27]) & 1) {
+ udelay(10);
+ timeout--;
+ continue;
+ } else
+ break;
+ };
+ if (timeout == 0)
+ DRM_ERROR("%s stop timeout\n", __func__);
+ else
+ DRM_DEBUG("%s stop Done %d\n", __func__, timeout);
+}
+
+static int dpu_modeset(struct spacemit_dpu *dpu, struct drm_mode_modeinfo *mode)
+{
+ return 0;
+}
+
+static void dpu_enable_vsync(struct spacemit_dpu *dpu)
+{
+ saturn_enable_vsync(dpu, true);
+}
+
+static void dpu_disable_vsync(struct spacemit_dpu *dpu)
+{
+ saturn_enable_vsync(dpu, false);
+}
+
+
+static struct dpu_core_ops dpu_saturn_ops = {
+ .parse_dt = dpu_parse_dt,
+ .version = dpu_get_version,
+ .init = dpu_init,
+ .uninit = dpu_uninit,
+ .run = dpu_run,
+ .stop = dpu_stop,
+ .isr = dpu_isr,
+ .modeset = dpu_modeset,
+ .enable_clk = dpu_enable_clocks,
+ .disable_clk = dpu_disable_clocks,
+ .update_clk = dpu_update_clocks,
+ .update_bw = dpu_update_bw,
+ .enable_vsync = dpu_enable_vsync,
+ .disable_vsync = dpu_disable_vsync,
+ .cal_layer_fbcmem_size = saturn_cal_layer_fbcmem_size,
+ .calc_plane_mclk_bw = dpu_calc_plane_mclk_bw,
+ .adjust_rdma_fbcmem = saturn_adjust_rdma_fbcmem,
+ .wb_config = saturn_wb_config,
+};
+
+static struct ops_entry entry = {
+ .ver = "spacemit-saturn",
+ .ops = &dpu_saturn_ops,
+};
+
+#ifndef MODULE
+static int __init dpu_core_register(void)
+#else
+int dpu_core_register(void)
+#endif
+{
+ return dpu_core_ops_register(&entry);
+}
+#ifndef MODULE
+subsys_initcall(dpu_core_register);
+#endif
+
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _DPU_SATURN_H_
+#define _DPU_SATURN_H_
+
+#include "saturn_regs/reg_map.h"
+#include "../spacemit_dpu.h"
+
+#ifndef min
+#define min(x, y) (((x)<(y))?(x):(y))
+#endif
+
+#ifndef max
+#define max(x, y) (((x)>(y))?(x):(y))
+#endif
+
+#ifndef clip
+#define clip(x, a, b) (max(a, min(x, b)))
+#endif
+
+/* Supported variants of the hardware */
+enum {
+ SATURN_HDMI = 0,
+ SATURN_LE,
+ /* keep the next entry last */
+ DP_MAX_DEVICES
+};
+
+struct dpu_format_id {
+ u32 format; /* DRM fourcc */
+ u8 id; /* used internally */
+ u8 bpp; /* bit per pixel */
+};
+
+#define SPACEMIT_DPU_INVALID_FORMAT_ID 0xff
+
+enum format_features {
+ FORMAT_RGB = BIT(0),
+ FORMAT_RAW_YUV = BIT(1),
+ FORMAT_AFBC = BIT(2),
+};
+
+enum rotation_features {
+ ROTATE_COMMON = BIT(0), /* supports rotation on raw and afbc 0/180, x and y */
+ ROTATE_RAW_90_270 = BIT(1), /* supports rotation on raw 90/270 */
+ ROTATE_AFBC_90_270 = BIT(2), /* supports rotation on afbc 90/270 */
+};
+
+struct spacemit_hw_rdma {
+ u16 formats;
+ u16 rots;
+};
+
+extern const u32 saturn_fbcmem_sizes[2];
+extern const u32 saturn_le_fbcmem_sizes[2];
+
+void spacemit_plane_update_hw_channel(struct drm_plane *plane);
+void spacemit_update_hdr_matrix(struct drm_plane *plane, struct spacemit_plane_state *spacemit_pstate);
+void spacemit_update_csc_matrix(struct drm_plane *plane, struct drm_plane_state *old_state);
+void spacemit_plane_disable_hw_channel(struct drm_plane *plane, struct drm_plane_state *old_state);
+void saturn_conf_dpuctrl_color_matrix(struct spacemit_dpu *dpu, struct drm_crtc_state *old_state);
+u8 spacemit_plane_hw_get_format_id(u32 format);
+extern struct spacemit_hw_device spacemit_dp_devices[DP_MAX_DEVICES];
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM dpu
+
+#if !defined(_DPU_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
+#define _DPU_TRACE_H_
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/tracepoint.h>
+
+#include "dpu_saturn.h"
+
+TRACE_EVENT(drm_display_mode_info,
+ TP_PROTO(struct drm_display_mode *mode),
+ TP_ARGS(mode),
+ TP_STRUCT__entry(
+ __field(u16, hdisplay)
+ __field(u16, hbp)
+ __field(u16, hfp)
+ __field(u16, hsync)
+ __field(u16, vdisplay)
+ __field(u16, vbp)
+ __field(u16, vfp)
+ __field(u16, vsync)
+ ),
+ TP_fast_assign(
+ __entry->hdisplay = mode->hdisplay;
+ __entry->hbp = mode->htotal - mode->hsync_end;
+ __entry->hfp = mode->hsync_start - mode->hdisplay;
+ __entry->hsync = mode->hsync_end - mode->hsync_start;
+ __entry->vdisplay = mode->vdisplay;
+ __entry->vbp = mode->vtotal - mode->vsync_end;
+ __entry->vfp = mode->vsync_start - mode->vdisplay;
+ __entry->vsync = mode->vsync_end - mode->vsync_start;
+ ),
+ TP_printk("drm_display_mode: hdisplay=%d vdisplay=%d hsync=%d vsync=%d hbp=%d hfp=%d vbp=%d vfp=%d",
+ __entry->hdisplay, __entry->vdisplay, __entry->hsync, __entry->vsync,
+ __entry->hbp, __entry->hfp, __entry->vbp, __entry->vfp
+ )
+);
+
+TRACE_EVENT(dpu_plane_info,
+ TP_PROTO(struct drm_plane_state *state, struct drm_framebuffer *fb,
+ u32 rdma_id, u32 alpha, u32 rotation, u32 afbc),
+ TP_ARGS(state, fb, rdma_id, alpha, rotation, afbc),
+ TP_STRUCT__entry(
+ __field(u32, rdma_id)
+ __field(u32, src_w)
+ __field(u32, src_h)
+ __field(u32, src_x)
+ __field(u32, src_y)
+ __field(u32, crtc_w)
+ __field(u32, crtc_h)
+ __field(u32, crtc_x)
+ __field(u32, crtc_y)
+ __field(u32, width)
+ __field(u32, height)
+ __field(u32, format)
+ __field(u32, blend_mode)
+ __field(u32, alpha)
+ __field(u32, zpos)
+ __field(u32, rotation)
+ __field(u32, afbc)
+ ),
+ TP_fast_assign(
+ __entry->rdma_id = rdma_id;
+ __entry->src_w = state->src_w >> 16;
+ __entry->src_h = state->src_h >> 16;
+ __entry->src_x = state->src_x >> 16;
+ __entry->src_y = state->src_y >> 16;
+ __entry->crtc_w = state->crtc_w;
+ __entry->crtc_h = state->crtc_h;
+ __entry->crtc_x = state->crtc_x;
+ __entry->crtc_y = state->crtc_y;
+ __entry->width = fb->width;
+ __entry->height = fb->height;
+ __entry->format = fb->format->format;
+ __entry->blend_mode = state->pixel_blend_mode;
+ __entry->alpha = alpha;
+ __entry->zpos = state->zpos;
+ __entry->rotation = rotation;
+ __entry->afbc = afbc;
+ ),
+ TP_printk("rdma_id=%d src: w=%d h=%d x=%d y=%d crtc: w=%d h=%d x=%d y=%d "
+ "width=%d height=%d fmt=0x%x blend=%d alpha:%d "
+ "zpos=%d rot:%d afbc:%d",
+ __entry->rdma_id, __entry->src_w,
+ __entry->src_h, __entry->src_x,
+ __entry->src_y, __entry->crtc_w,
+ __entry->crtc_h, __entry->crtc_x,
+ __entry->crtc_y, __entry->width,
+ __entry->height, __entry->format,
+ __entry->blend_mode, __entry->alpha,
+ __entry->zpos, __entry->rotation,
+ __entry->afbc)
+);
+
+DECLARE_EVENT_CLASS(dpu_status_template,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status),
+ TP_STRUCT__entry(
+ __string(name_str, name)
+ __field(int, status)
+ ),
+ TP_fast_assign(
+ __assign_str(name_str, name);
+ __entry->status = status;
+ ),
+ TP_printk("%s: 0x%x",
+ __get_str(name_str), __entry->status)
+);
+
+DEFINE_EVENT(dpu_status_template, dpuctrl_scaling,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+DEFINE_EVENT(dpu_status_template, dpuctrl,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+DEFINE_EVENT(dpu_status_template, spacemit_plane_update_hw_channel,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+DEFINE_EVENT(dpu_status_template, saturn_irq_enable,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+DEFINE_EVENT(dpu_status_template, saturn_enable_vsync,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+DEFINE_EVENT(dpu_status_template, dpu_isr_status,
+ TP_PROTO(const char *name, int status),
+ TP_ARGS(name, status)
+);
+
+DECLARE_EVENT_CLASS(dpu_ul_data_template,
+ TP_PROTO(const char *name, unsigned long ul_data),
+ TP_ARGS(name, ul_data),
+ TP_STRUCT__entry(
+ __string(name_str, name)
+ __field(unsigned long, ul_data)
+ ),
+ TP_fast_assign(
+ __assign_str(name_str, name);
+ __entry->ul_data = ul_data;
+ ),
+ TP_printk("%s: %ld",
+ __get_str(name_str), __entry->ul_data)
+);
+
+DEFINE_EVENT(dpu_ul_data_template, dpu_isr_ul_data,
+ TP_PROTO(const char *name, unsigned long ul_data),
+ TP_ARGS(name, ul_data)
+);
+
+DECLARE_EVENT_CLASS(dpu_uint64_t_data_template,
+ TP_PROTO(const char *name, uint64_t data),
+ TP_ARGS(name, data),
+ TP_STRUCT__entry(
+ __string(name_str, name)
+ __field(uint64_t, data)
+ ),
+ TP_fast_assign(
+ __assign_str(name_str, name);
+ __entry->data = data;
+ ),
+ TP_printk("%s: %lld",
+ __get_str(name_str), __entry->data)
+);
+
+DEFINE_EVENT(dpu_uint64_t_data_template, u64_data,
+ TP_PROTO(const char *name, uint64_t data),
+ TP_ARGS(name, data)
+);
+
+TRACE_EVENT(spacemit_plane_disable_hw_channel,
+ TP_PROTO(uint32_t layer_id, uint32_t rdma_id),
+ TP_ARGS(layer_id, rdma_id),
+ TP_STRUCT__entry(
+ __field(uint32_t, layer_id)
+ __field(uint32_t, rdma_id)
+ ),
+ TP_fast_assign(
+ __entry->layer_id = layer_id;
+ __entry->rdma_id = rdma_id;
+ ),
+ TP_printk("layer_id:%d rdma_id:%d",
+ __entry->layer_id, __entry->rdma_id)
+);
+
+TRACE_EVENT(dpu_mclk_scl,
+ TP_PROTO(uint64_t in_width, uint64_t in_height, uint64_t out_width, uint64_t out_height, uint64_t bpp, uint64_t C, uint64_t width_ratio, uint64_t height_ratio),
+ TP_ARGS(in_width, in_height, out_width, out_height, bpp, C, width_ratio, height_ratio),
+ TP_STRUCT__entry(
+ __field(uint64_t, in_width)
+ __field(uint64_t, in_height)
+ __field(uint64_t, out_width)
+ __field(uint64_t, out_height)
+ __field(uint64_t, bpp)
+ __field(uint64_t, C)
+ __field(uint64_t, width_ratio)
+ __field(uint64_t, height_ratio)
+ ),
+ TP_fast_assign(
+ __entry->in_width = in_width;
+ __entry->in_height = in_height;
+ __entry->out_width = out_width;
+ __entry->out_height = out_height;
+ __entry->bpp = bpp;
+ __entry->C = C;
+ __entry->width_ratio = width_ratio;
+ __entry->height_ratio = height_ratio;
+ ),
+ TP_printk("scl_in_width = %lld, scl_in_height = %lld, scl_out_width = %lld, scl_out_height = %lld, bpp = %lld, C = %lld, width_ratio = %lld, height_ratio = %lld \n",
+ __entry->in_width, __entry->in_height, __entry->out_width,
+ __entry->out_height, __entry->bpp, __entry->C,
+ __entry->width_ratio, __entry->height_ratio)
+);
+
+TRACE_EVENT(dpu_fpixclk_hblk,
+ TP_PROTO(uint64_t hact, uint64_t fps, uint64_t vtotal, uint64_t fpixclk_hblk),
+ TP_ARGS(hact, fps, vtotal, fpixclk_hblk),
+ TP_STRUCT__entry(
+ __field(uint64_t, hact)
+ __field(uint64_t, fps)
+ __field(uint64_t, vtotal)
+ __field(uint64_t, fpixclk_hblk)
+ ),
+ TP_fast_assign(
+ __entry->hact = hact;
+ __entry->fps = fps;
+ __entry->vtotal = vtotal;
+ __entry->fpixclk_hblk = fpixclk_hblk;
+ ),
+ TP_printk("hact = %lld, fps = %lld, vtotal = %lld, Fpixclk_hblk = %lld\n",
+ __entry->hact, __entry->fps, __entry->vtotal, __entry->fpixclk_hblk)
+);
+
+TRACE_EVENT(dpuctrl_scaling_setting,
+ TP_PROTO(uint32_t id, int in_use, int rdma_id),
+ TP_ARGS(id, in_use, rdma_id),
+ TP_STRUCT__entry(
+ __field(uint32_t, id)
+ __field(int, in_use)
+ __field(int, rdma_id)
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->in_use = in_use;
+ __entry->rdma_id = rdma_id;
+ ),
+ TP_printk("scaler%d: in_use:0x%x rdma_id:%d",
+ __entry->id, __entry->in_use, __entry->rdma_id)
+);
+
+TRACE_EVENT(dpu_reg_info,
+ TP_PROTO(u8* mod_name, phys_addr_t p_addr, uint32_t reg_num),
+ TP_ARGS(mod_name, p_addr, reg_num),
+ TP_STRUCT__entry(
+ __string(name_str, mod_name)
+ __field(phys_addr_t, p_addr)
+ __field(uint32_t, reg_num)
+ ),
+ TP_fast_assign(
+ __assign_str(name_str, mod_name);
+ __entry->p_addr = p_addr;
+ __entry->reg_num = reg_num;
+ ),
+ TP_printk("%s(0x%08llx), num:%d",
+ __get_str(name_str), __entry->p_addr, __entry->reg_num)
+);
+
+TRACE_EVENT(dpu_reg_dump,
+ TP_PROTO(uint32_t reg, uint32_t val),
+ TP_ARGS(reg, val),
+ TP_STRUCT__entry(
+ __field(uint32_t, reg)
+ __field(uint32_t, val)
+ ),
+ TP_fast_assign(
+ __entry->reg = reg;
+ __entry->val = val;
+ ),
+ TP_printk("0x%08x: 0x%08x",
+ __entry->reg, __entry->val)
+);
+
+DECLARE_EVENT_CLASS(dpu_func_template,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id),
+ TP_STRUCT__entry(
+ __field(uint32_t, dev_id)
+ ),
+ TP_fast_assign(
+ __entry->dev_id = dev_id;
+ ),
+ TP_printk("dev_id=%d", __entry->dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_check_rdma,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_check,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_update,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_reset,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_duplicate_state,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_atomic_destroy_state,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_plane_init,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_enable_clocks,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_disable_clocks,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, saturn_wait_for_cfg_ready,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, saturn_wait_for_eof,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, saturn_wait_for_wb,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, saturn_run_display,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_init,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_uninit,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_isr,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_run,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, dpu_stop,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_mode_set_nofb,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_enable,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_disable,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_check,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_begin,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_atomic_flush,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_enable_vblank,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_crtc_disable_vblank,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_dpu_run,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_dpu_stop,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_dpu_init,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+DEFINE_EVENT(dpu_func_template, spacemit_dpu_uninit,
+ TP_PROTO(uint32_t dev_id),
+ TP_ARGS(dev_id)
+);
+
+DECLARE_EVENT_CLASS(dpu_ctrl_template,
+ TP_PROTO(int id, int enable),
+ TP_ARGS(id, enable),
+ TP_STRUCT__entry(
+ __field(uint32_t, id)
+ __field(uint32_t, enable)
+ ),
+ TP_fast_assign(
+ __entry->id = id;
+ __entry->enable = enable;
+ ),
+ TP_printk("id=%d enable:%d",
+ __entry->id, __entry->enable)
+);
+DEFINE_EVENT(dpu_ctrl_template, saturn_ctrl_cfg_ready,
+ TP_PROTO(int id, int enable),
+ TP_ARGS(id, enable)
+);
+DEFINE_EVENT(dpu_ctrl_template, saturn_ctrl_sw_start,
+ TP_PROTO(int id, int enable),
+ TP_ARGS(id, enable)
+);
+
+
+TRACE_EVENT(saturn_conf_scaler_x,
+ TP_PROTO(struct spacemit_plane_state *state),
+ TP_ARGS(state),
+ TP_STRUCT__entry(
+ __field(int, id)
+ ),
+ TP_fast_assign(
+ __entry->id = state->scaler_id;
+ ),
+ TP_printk("scaler_id:%d", __entry->id)
+);
+
+
+#endif /* _DPU_TRACE_H_ */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_FILE
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH ../../drivers/gpu/drm/spacemit/dpu/
+
+#define TRACE_INCLUDE_FILE dpu_trace
+#include <trace/define_trace.h>
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/stddef.h>
+#include <linux/export.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_print.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_fourcc.h>
+#include "../spacemit_cmdlist.h"
+#include "saturn_fbcmem.h"
+
+static int get_fbc_block_size_by_modifier(uint64_t modifier, u32* out_fbc_block_size) {
+ int ret_val = 0;
+ uint64_t super_block_size = modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK;
+
+ if (super_block_size == AFBC_FORMAT_MOD_BLOCK_SIZE_16x16) {
+ *out_fbc_block_size = FBC_BLOCK_SIZE_16x16;
+ } else if (super_block_size == AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) {
+ *out_fbc_block_size = FBC_BLOCK_SIZE_32x8;
+ } else {
+ DRM_ERROR("FBC_MEM: failed to get fbc block size info for modifier = 0x%llx\n", super_block_size);
+ ret_val = -1;
+ }
+
+ return ret_val;
+}
+
+static bool is_bpp32_in_fbc_mem_cal(uint32_t drm_4cc_fmt) {
+ bool is_taken_as_bpp32 = false;
+ const struct drm_format_info *info = NULL;
+
+ info = drm_format_info(drm_4cc_fmt);
+ if (info->num_planes == 1 && info->cpp[0] == 4) {
+ is_taken_as_bpp32 = true;
+ } else {
+ switch (drm_4cc_fmt) {
+ case DRM_FORMAT_RGB888: //RDMA_FMT_RGB_888:
+ case DRM_FORMAT_BGR888: //RDMA_FMT_BGR_888:
+ is_taken_as_bpp32 = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return is_taken_as_bpp32;
+}
+
+static u32 adjust_afbc_layer_mem_size(u8 rdma_work_mode, u32 drm_4cc_fmt, u32 fbc_block_size, bool rot_90_or_270, u32 fbcmem_size) {
+ u32 ret_size = fbcmem_size;
+ bool is_bpp_32 = is_bpp32_in_fbc_mem_cal(drm_4cc_fmt);
+
+ //if left_right mode fbc_layout 32x8, is_bpp_32 and not rotation 90/270, hw request double mem_size.
+ if ((rdma_work_mode == LEFT_RIGHT) && (fbc_block_size == FBC_BLOCK_SIZE_32x8) && is_bpp_32 && (rot_90_or_270 == false)) {
+ ret_size *= 2;
+ }
+ DRM_DEBUG("FBC_MEM: %s, rdma_mode = %u, is_bpp_32 = %d, fbc_block_size = %u, rot_90_or_270 = %d, input = %u, ret = %u\n",
+ __func__, rdma_work_mode, is_bpp_32, fbc_block_size, rot_90_or_270, fbcmem_size, ret_size);
+
+ return ret_size;
+}
+
+int get_raw_data_plane_rdma_mem_size(u32 drm_4cc_fmt, bool rot_90_or_270, u32 plane_crop_width, u32* output_mem_size) {
+ u8 index = 0;
+ u32 ret_mem_size = 0;
+ u32 data_plane_mem_size[3] = {0}; //max 3 plane, YUV data
+ const struct drm_format_info *info = NULL;
+ //struct drm_format_name_buf fmt_name = {0};
+
+ //drm_get_format_name(drm_4cc_fmt, &fmt_name);
+ if (rot_90_or_270) {
+ ret_mem_size = 1024; //dpu hardware request 32K fix size, 32 byte unit has considered
+ } else {
+ info = drm_format_info(drm_4cc_fmt);
+ if (info->cpp[0] == 0) {
+ DRM_ERROR("FBC_MEM: not support format %d\n", drm_4cc_fmt);
+ return -1;
+ }
+ if (info->num_planes == 1 && info->is_yuv == false) {
+ data_plane_mem_size[0] = plane_crop_width * info->cpp[0];
+ } else if (info->num_planes >= 2 && info->is_yuv) {
+ data_plane_mem_size[0] = plane_crop_width * info->cpp[0];
+ data_plane_mem_size[1] = plane_crop_width * info->cpp[1]/info->hsub;
+ if (info->num_planes == 3) {
+ data_plane_mem_size[2] = plane_crop_width * info->cpp[2]/info->vsub;
+ }
+ } else {
+ DRM_ERROR("FBC_MEM: not considered drm format %d\n", drm_4cc_fmt);
+ return -1;
+ }
+ for (index = 0; index < info->num_planes; index++) { //max 3 plane, YUV data
+ data_plane_mem_size[index] = roundup(data_plane_mem_size[index], 64); //dpu hardware request
+ ret_mem_size += data_plane_mem_size[index];
+ }
+ ret_mem_size = roundup(ret_mem_size, 64);
+ ret_mem_size = ret_mem_size/32;
+ }
+ if (output_mem_size) {
+ *output_mem_size = ret_mem_size;
+ DRM_DEBUG("FBC_MEM: raw layer, fmt = %d, rot_90_270 = %d, crop_w = %u, cal memsize = %u\n",
+ drm_4cc_fmt, rot_90_or_270, plane_crop_width, *output_mem_size);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(get_raw_data_plane_rdma_mem_size);
+
+int get_afbc_data_plane_min_rdma_mem_size(u8 rdma_work_mode, u32 drm_4cc_fmt,
+ u32 crop_start_x, u32 crop_start_y, u32 crop_width, u32 crop_height,
+ u32 fbc_block_size, bool rot_90_or_270, u8 min_lines, u32* output_mem_size) {
+ bool is_bpp_32 = false;
+ uint32_t ret_mem_size = 0;
+ uint32_t crop_start_align = 0;
+ uint32_t crop_end_align = 0;
+ uint32_t bbox_width = 0;
+ uint32_t num_addr_per_line = 0;
+ uint32_t num_addr_frac4 = 0;
+ uint32_t num_addr_4line = 0;
+ uint32_t num_addr_frac8 = 0;
+ uint32_t num_addr_8line = 0;
+ uint32_t align_num = (fbc_block_size == FBC_BLOCK_SIZE_16x16) ? 16 : 32;
+ //struct drm_format_name_buf fmt_name = {0};
+
+ //drm_get_format_name(drm_4cc_fmt, &fmt_name);
+ DRM_DEBUG("FBC_MEM: afbc layer, fmt = %d, \
+ crop_x = %u, crop_y = %u, crop_w = %u, crop_h = %u, \
+ fbc_block_size = %u, rot_90_270 = %u, min_lines = %u, rdma_mode = %u\n",
+ drm_4cc_fmt, crop_start_x, crop_start_y, crop_width,
+ crop_height, fbc_block_size, rot_90_or_270, min_lines, rdma_work_mode);
+
+ if (rot_90_or_270) {
+ crop_start_align = rounddown(crop_start_y, align_num);
+ crop_end_align = roundup(crop_start_y + crop_height, align_num) - 1;
+ } else {
+ crop_start_align = rounddown(crop_start_x, align_num);
+ crop_end_align = roundup(crop_start_x + crop_width, align_num) - 1;
+ }
+
+ bbox_width = crop_end_align - crop_start_align + 1;
+ is_bpp_32 = is_bpp32_in_fbc_mem_cal(drm_4cc_fmt);
+ num_addr_per_line = is_bpp_32 ? bbox_width/8 : bbox_width/16;
+
+ if (min_lines == 4) {
+ num_addr_frac4 = (num_addr_per_line % 8 == 0) ? num_addr_per_line/8 : (num_addr_per_line/8 + 1);
+ num_addr_4line = num_addr_frac4 * 8 * 4;
+ ret_mem_size = num_addr_4line;
+ } else if (min_lines == 8) {
+ num_addr_frac8 = (num_addr_per_line % 16 == 0) ? num_addr_per_line/16 : (num_addr_per_line/16 + 1);
+ num_addr_8line = num_addr_frac8 * 16 * 8;
+ ret_mem_size = num_addr_8line;
+ }
+
+ ret_mem_size = adjust_afbc_layer_mem_size(rdma_work_mode, drm_4cc_fmt, fbc_block_size, rot_90_or_270, ret_mem_size);
+ *output_mem_size = ret_mem_size;
+
+ DRM_DEBUG("FBC_MEM: afbc layer, fmt = %d, \
+ crop_x = %u, crop_y = %u, crop_w = %u, crop_h = %u, \
+ fbc_block_size = %u, rot_90_270 = %u, min_lines = %u, rdma_mode = %u, cal memsize = %u\n",
+ drm_4cc_fmt, crop_start_x, crop_start_y, crop_width,
+ crop_height, fbc_block_size, rot_90_or_270, min_lines, rdma_work_mode, *output_mem_size);
+
+ return 0;
+}
+EXPORT_SYMBOL(get_afbc_data_plane_min_rdma_mem_size);
+
+void inline saturn_write_fbcmem_regs(struct drm_plane_state *state, u32 rdma_id,
+ u32 module_base, volatile RDMA_PATH_X_REG *rdma_regs)
+{
+ struct drm_crtc_state *crtc_state = state->crtc->state;
+ struct drm_crtc *crtc = crtc_state->crtc;
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ const struct spacemit_dpu_rdma *rdmas = to_spacemit_crtc_state(crtc_state)->rdmas;
+ u32 size = rdmas[rdma_id].fbcmem.size;// / FBCMEM_UNIT;
+ u32 start = rdmas[rdma_id].fbcmem.start;// / FBCMEM_UNIT;
+ bool map = rdmas[rdma_id].fbcmem.map;
+
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, module_base, FBC_MEM_SIZE, map << 28 | start << 16 | size);
+
+ return;
+}
+
+int saturn_cal_layer_fbcmem_size(struct drm_plane *plane, \
+ struct drm_plane_state *state)
+{
+ int ret = 0;
+ //u32 adjust_fbcmem_size = 0;
+ struct spacemit_plane_state *pstate = to_spacemit_plane_state(state);
+ uint64_t modifier = pstate->state.fb->modifier;
+
+ u32 drm_4cc_fmt = pstate->state.fb->format->format;
+ unsigned int rotation = pstate->state.rotation;
+ bool rot_90_or_270 = (rotation & DRM_MODE_ROTATE_90) || (rotation & DRM_MODE_ROTATE_270);
+ u32 crop_x = pstate->state.src_x >> 16; //check
+ u32 crop_y = pstate->state.src_y >> 16; //check
+ u32 crop_w = pstate->state.src_w >> 16; //check
+ u32 crop_h = pstate->state.src_h >> 16; //check
+ u32 fbc_block_size = FBC_BLOCK_SIZE_LIMIT;
+ struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state->state, state->crtc);
+ const struct spacemit_dpu_rdma *rdmas = to_spacemit_crtc_state(crtc_state)->rdmas;
+ u8 rdma_work_mode = rdmas[pstate->rdma_id].mode;
+ u8 min_lines = 4; //TODO
+
+ if (modifier == 0) { //raw data layer
+ ret = get_raw_data_plane_rdma_mem_size(drm_4cc_fmt, rot_90_or_270, crop_w, &(pstate->fbcmem_size));
+ } else { //afbc data layer
+ ret = get_fbc_block_size_by_modifier(modifier, &fbc_block_size);
+ if (ret < 0) {
+ DRM_ERROR("FBC_MEM: failed to get fbc block size info for modifier = 0x%llx\n", modifier);
+ return -1;
+ }
+ if (modifier && drm_4cc_fmt == DRM_FORMAT_YUV420_8BIT) { //video layer
+ min_lines = 8; //dpu hardware request 8 line at least
+ }
+ ret = get_afbc_data_plane_min_rdma_mem_size(rdma_work_mode, drm_4cc_fmt, crop_x, crop_y,
+ crop_w, crop_h, fbc_block_size, rot_90_or_270, min_lines, &(pstate->fbcmem_size));
+ }
+ if (ret < 0) {
+ DRM_ERROR("FBC_MEM: faied to get plane mem size for plane: src_x = %u, scr_y = %u, src_h = %u, src_w = %u\n",
+ pstate->state.src_x, pstate->state.src_y, pstate->state.src_h, pstate->state.src_w);
+ }
+
+ return ret;
+}
+
+int saturn_adjust_rdma_fbcmem(struct spacemit_hw_device *hwdev, \
+ struct spacemit_dpu_rdma *rdmas)
+{
+ int ret = -1;
+ u8 index = 0;
+ u8 sec_fbcmem_index = 0;
+ u32 pri_fbcmem_size = 0;
+ u32 sec_fbcmem_size = 0;
+ u32* fbc_mems_left = NULL;
+ u32 cur_rdma_fbcmem_size = 0;
+ u8 rdma_nums = hwdev->rdma_nums;
+ bool pre_odd_rdma_use_shared_fbc_mem = false;
+
+ struct spacemit_dpu_fbcmem * fbcmem = NULL;
+ for (index = 0; index < rdma_nums; index++) {
+ fbcmem = &(rdmas[index].fbcmem);
+ DRM_DEBUG("input rdmas[%u/%u]: mode = %d, start = %d, size = %d, map = %d\n",
+ index, rdma_nums, rdmas[index].mode, fbcmem->start, fbcmem->size, fbcmem->map);
+ }
+
+ fbc_mems_left = kzalloc(sizeof(u32) * (rdma_nums/2), GFP_KERNEL);
+ if (fbc_mems_left == NULL) {
+ DRM_ERROR("FBC_MEM: No memory left!\n");
+ goto free;
+ }
+ for (index = 0; index < rdma_nums/2; index++) {
+ fbc_mems_left[index] = hwdev->fbcmem_sizes[index] / FBCMEM_UNIT;
+ DRM_DEBUG("fbcmem_sizes[%u/%u] = %u, total fbc_mems_left = %u\n",
+ index, rdma_nums/2, hwdev->fbcmem_sizes[index], fbc_mems_left[index]);
+ if (fbc_mems_left[index] == 0) {
+ DRM_ERROR("FBC_MEM: error fbcmem_sizes[%d] = %u\n", index, hwdev->fbcmem_sizes[index]);
+ goto free;
+ }
+ }
+
+ for (index = 0; index < rdma_nums; index++) {
+ cur_rdma_fbcmem_size = rdmas[index].fbcmem.size;
+ if (cur_rdma_fbcmem_size == 0) {
+ DRM_DEBUG("return directly for rmda %u fbcmem size is 0\n", index);
+ continue;
+ }
+ pri_fbcmem_size = hwdev->fbcmem_sizes[index/2] / FBCMEM_UNIT;
+
+ if (index % 2 == 0) { //dma_id is even: 0, 2, 4, 6...
+ DRM_DEBUG("rdma%u, cur_rdma_fbcmem_size = %u, pri_fbcmem_size = %u\n",
+ index, cur_rdma_fbcmem_size, pri_fbcmem_size);
+ if (cur_rdma_fbcmem_size > pri_fbcmem_size) {
+ DRM_ERROR("FBC_MEM: rdma %d use %d byte, excess the size %d\n",
+ index, cur_rdma_fbcmem_size, pri_fbcmem_size);
+ goto free;
+ }
+ if (index > 0) {
+ pre_odd_rdma_use_shared_fbc_mem = rdmas[index - 1].fbcmem.map;
+ if (pre_odd_rdma_use_shared_fbc_mem) {
+ DRM_ERROR("FBC_MEM: both rdma %d %d use fbc memory\n", index, index - 1);
+ goto free;
+ }
+ }
+ rdmas[index].fbcmem.start = 0;
+ rdmas[index].fbcmem.map = true;
+ fbc_mems_left[index/2] -= cur_rdma_fbcmem_size;
+ DRM_DEBUG("FBC_MEM: rdma: id = %d, size = %u, start = %u, map = %u, fbc_mems_left[%u] = %d\n",
+ index, cur_rdma_fbcmem_size, rdmas[index].fbcmem.start, rdmas[index].fbcmem.map, index/2, fbc_mems_left[index/2]);
+ } else { //odd rdma: rdma 1, 3, 5...
+ if (cur_rdma_fbcmem_size <= fbc_mems_left[index/2]) { //not share fbc mem
+ DRM_DEBUG("rdma%u, cur_rdma_fbcmem_size = %u, fbc_mems_left[%u] = %u\n",
+ index, cur_rdma_fbcmem_size, index/2, fbc_mems_left[index/2]);
+ rdmas[index].fbcmem.map = false;
+ rdmas[index].fbcmem.start = pri_fbcmem_size - fbc_mems_left[index/2];
+ rdmas[index].fbcmem.size = fbc_mems_left[index/2];//use all the mem left
+ fbc_mems_left[index/2] = 0;
+ DRM_DEBUG("FBC_MEM: rdma: id = %d, size = %u, actually size = %u, start = %u, map = %u, fbc_mems_left[%u] = 0\n",
+ index, cur_rdma_fbcmem_size, rdmas[index].fbcmem.size, rdmas[index].fbcmem.start, rdmas[index].fbcmem.map, index/2);
+ } else { //need share fbc mem
+ sec_fbcmem_index = (index/2 + 1)%(rdma_nums/2);
+ sec_fbcmem_size = hwdev->fbcmem_sizes[sec_fbcmem_index] / FBCMEM_UNIT;
+ DRM_DEBUG("rdma%u, cur_rdma_fbcmem_size = %u, fbc_mems_left[%u] = %d, sec_fbcmem_size = %u\n",
+ index, cur_rdma_fbcmem_size, index/2, fbc_mems_left[index/2], sec_fbcmem_size);
+ if (cur_rdma_fbcmem_size > fbc_mems_left[index/2] + sec_fbcmem_size) {
+ DRM_ERROR("FBC_MEM: rdma %d use %d mem size, but left %d\n",
+ index, cur_rdma_fbcmem_size, fbc_mems_left[index/2] + sec_fbcmem_size);
+ goto free;
+ } else {
+ if (index == rdma_nums - 1) { //last rdma id
+ if (fbc_mems_left[0] != hwdev->fbcmem_sizes[0] / FBCMEM_UNIT) { //fbc mem0 has used
+ DRM_ERROR("FBC_MEM: rdma %d can not use fbc mem 0 for it has been used\n", index);
+ goto free;
+ } else {
+ rdmas[index].fbcmem.size = fbc_mems_left[index/2] + sec_fbcmem_size;
+ cur_rdma_fbcmem_size = rdmas[index].fbcmem.size;
+ }
+ }
+ fbc_mems_left[sec_fbcmem_index] -= (cur_rdma_fbcmem_size - fbc_mems_left[index/2]);
+ DRM_DEBUG("rmda%u, fbc_mems_left[%u] = %d, fbc_mems_left[%u] = %u\n",
+ index, index/2, fbc_mems_left[index/2], sec_fbcmem_index, fbc_mems_left[sec_fbcmem_index]);
+ rdmas[index].fbcmem.start = pri_fbcmem_size - fbc_mems_left[index/2];
+ rdmas[index].fbcmem.map = true;
+ fbc_mems_left[index/2] = 0;
+
+ fbcmem = &(rdmas[index].fbcmem);
+ DRM_DEBUG("FBC_MEM: rdma: id = %d, actually size = %u, start = %u, map = %u\n",
+ index, fbcmem->size, fbcmem->start, fbcmem->map);
+ }
+ }
+ }
+ }
+ ret = 0;
+
+free:
+ if (fbc_mems_left) {
+ kfree(fbc_mems_left);
+ }
+
+ return ret;
+}
+
+EXPORT_SYMBOL(saturn_adjust_rdma_fbcmem);
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SATURN_FBCMEM_H_
+#define _SATURN_FBCMEM_H_
+
+#include <drm/drm_plane.h>
+#include "../spacemit_dpu.h"
+#include "../spacemit_dpu_reg.h"
+#include "dpu_saturn.h"
+#include "saturn_regs/reg_map.h"
+
+#define FBCMEM_UNIT (32) //fbcmem is 32 bytes per unit
+
+typedef enum FBC_BLOCK_SIZE_E {
+ FBC_BLOCK_SIZE_16x16, //0
+ FBC_BLOCK_SIZE_32x8, //1
+ FBC_BLOCK_SIZE_LIMIT, //error block size
+} FBC_BLOCK_SIZE_T;
+
+int get_raw_data_plane_rdma_mem_size(u32 drm_4cc_fmt, bool rot_90_or_270,
+ u32 plane_crop_width, u32* output_mem_size);
+
+int get_afbc_data_plane_min_rdma_mem_size(u8 rdma_work_mode, u32 drm_4cc_fmt,
+ u32 crop_start_x, u32 crop_start_y, u32 crop_width, u32 crop_height,
+ u32 fbc_block_size, bool rot_90_or_270, u8 min_lines, u32* output_mem_size);
+
+int saturn_cal_layer_fbcmem_size(struct drm_plane *plane, \
+ struct drm_plane_state *state);
+
+int saturn_adjust_rdma_fbcmem(struct spacemit_hw_device *hwdev, \
+ struct spacemit_dpu_rdma *rdmas);
+
+void inline saturn_write_fbcmem_regs(struct drm_plane_state *state, u32 rdma_id,
+ u32 module_base, volatile RDMA_PATH_X_REG *rdma_regs);
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef CMDLIST_REG_H
+#define CMDLIST_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER cmdlist_reg_0
+ struct
+ {
+ UINT32 : 4 ;
+ UINT32 cmdlist_ch_start_addrl : 28;
+ }cmdlist_reg_0[14];
+
+ //REGISTER cmdlist_reg_14
+ struct
+ {
+ UINT32 cmdlist_ch_start_addrh : 2 ;
+ UINT32 : 6 ;
+ UINT32 cmdlist_ch_y : 16;
+ UINT32 : 8 ;
+ }cmdlist_reg_14[14];
+
+ //REGISTER cmdlist_reg_28
+ UINT32 cmdlist_burst_len : 5 ;
+ UINT32 axi_port_sel : 2 ;
+ UINT32 onl_arb_ratio : 3 ;
+ UINT32 : 22;
+
+
+ //REGISTER cmdlist_reg_29
+ UINT32 cmdlist_clr : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER cmdlist_reg_30
+ UINT32 : 16;
+ UINT32 cmdlist_clr_timeout_th : 16;
+
+
+ //REGISTER cmdlist_reg_31
+ UINT32 : 4 ;
+ UINT32 cmdlist_ch_cfg_timeout_int_msk : 14;
+ UINT32 cmdlist_ch_clr_timeout_int_msk : 14;
+
+
+ //REGISTER cmdlist_reg_32
+ UINT32 : 32;
+
+
+ //REGISTER cmdlist_reg_33
+ UINT32 : 4 ;
+ UINT32 cmdlist_ch_cfg_timeout_ints : 14;
+ UINT32 cmdlist_ch_clr_timeout_ints : 14;
+
+
+ //REGISTER cmdlist_reg_34
+ UINT32 : 32;
+
+
+ //REGISTER cmdlist_reg_35
+ UINT32 : 4 ;
+ UINT32 cmdlist_ch_cfg_timeout_int_raw : 14;
+ UINT32 cmdlist_ch_clr_timeout_int_raw : 14;
+
+
+ //REGISTER cmdlist_reg_36
+ struct
+ {
+ UINT32 cmdlist_ch_dbg0 : 11;
+ UINT32 : 5 ;
+ UINT32 cmdlist_ch_dbg1 : 11;
+ UINT32 : 5 ;
+ }cmdlist_reg_36[7];
+
+ //REGISTER cmdlist_reg_43
+ UINT32 cmdlist_dbg : 6 ;
+ UINT32 : 26;
+
+
+ };
+
+ INT32 value32[44];
+
+}CMDLIST_REG;
+
+#define CMDLIST_ADDRL_ALIGN_BITS (4) //From cmdlist_reg_0[] in CMDLIST_REG
+#define CMDLIST_ADDRL_ALIGN_MASK ((u32)(~(BIT(CMDLIST_ADDRL_ALIGN_BITS) - 1)))
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef CMPS_X_REG_H
+#define CMPS_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER dpu_cmps_reg_0
+ UINT32 m_ncmps_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_noutput_width : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_1
+ UINT32 m_noutput_height : 16;
+ UINT32 : 16;
+
+
+ //REGISTER dpu_cmps_reg_2
+ UINT32 m_nbg_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_3
+ UINT32 m_nbg_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_4
+ UINT32 m_nbg_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_5
+ UINT32 m_nbg_color_A : 8 ;
+ UINT32 : 24;
+
+
+ //REGISTER dpu_cmps_reg_6
+ UINT32 m_nl0_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl1_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_7
+ UINT32 m_nl2_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl3_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_8
+ UINT32 m_nl4_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl5_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_9
+ UINT32 m_nl6_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl7_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_10
+ UINT32 m_nl8_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl9_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_11
+ UINT32 m_nl10_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl11_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_12
+ UINT32 m_nl12_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl13_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_13
+ UINT32 m_nl14_solid_color_A : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl15_solid_color_A : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_14
+ UINT32 m_nl0_en : 1 ;
+ UINT32 m_nl0_layer_id : 4 ;
+ UINT32 m_nl0_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_15
+ UINT32 m_nl0_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_16
+ UINT32 m_nl0_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_17
+ UINT32 m_nl0_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_18
+ UINT32 m_nl0_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl0_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_19
+ UINT32 m_nl0_rect_ltopy : 16;
+ UINT32 m_nl0_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_20
+ UINT32 m_nl0_rect_rboty : 16;
+ UINT32 m_nl0_blend_mode : 2 ;
+ UINT32 m_nl0_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_21
+ UINT32 m_nl0_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl0_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_22
+ UINT32 m_nl1_en : 1 ;
+ UINT32 m_nl1_layer_id : 4 ;
+ UINT32 m_nl1_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_23
+ UINT32 m_nl1_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_24
+ UINT32 m_nl1_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_25
+ UINT32 m_nl1_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_26
+ UINT32 m_nl1_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl1_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_27
+ UINT32 m_nl1_rect_ltopy : 16;
+ UINT32 m_nl1_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_28
+ UINT32 m_nl1_rect_rboty : 16;
+ UINT32 m_nl1_blend_mode : 2 ;
+ UINT32 m_nl1_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_29
+ UINT32 m_nl1_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl1_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_30
+ UINT32 m_nl2_en : 1 ;
+ UINT32 m_nl2_layer_id : 4 ;
+ UINT32 m_nl2_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_31
+ UINT32 m_nl2_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_32
+ UINT32 m_nl2_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_33
+ UINT32 m_nl2_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_34
+ UINT32 m_nl2_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl2_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_35
+ UINT32 m_nl2_rect_ltopy : 16;
+ UINT32 m_nl2_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_36
+ UINT32 m_nl2_rect_rboty : 16;
+ UINT32 m_nl2_blend_mode : 2 ;
+ UINT32 m_nl2_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_37
+ UINT32 m_nl2_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl2_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_38
+ UINT32 m_nl3_en : 1 ;
+ UINT32 m_nl3_layer_id : 4 ;
+ UINT32 m_nl3_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_39
+ UINT32 m_nl3_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_40
+ UINT32 m_nl3_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_41
+ UINT32 m_nl3_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_42
+ UINT32 m_nl3_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl3_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_43
+ UINT32 m_nl3_rect_ltopy : 16;
+ UINT32 m_nl3_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_44
+ UINT32 m_nl3_rect_rboty : 16;
+ UINT32 m_nl3_blend_mode : 2 ;
+ UINT32 m_nl3_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_45
+ UINT32 m_nl3_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl3_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_46
+ UINT32 m_nl4_en : 1 ;
+ UINT32 m_nl4_layer_id : 4 ;
+ UINT32 m_nl4_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_47
+ UINT32 m_nl4_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_48
+ UINT32 m_nl4_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_49
+ UINT32 m_nl4_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_50
+ UINT32 m_nl4_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl4_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_51
+ UINT32 m_nl4_rect_ltopy : 16;
+ UINT32 m_nl4_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_52
+ UINT32 m_nl4_rect_rboty : 16;
+ UINT32 m_nl4_blend_mode : 2 ;
+ UINT32 m_nl4_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_53
+ UINT32 m_nl4_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl4_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_54
+ UINT32 m_nl5_en : 1 ;
+ UINT32 m_nl5_layer_id : 4 ;
+ UINT32 m_nl5_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_55
+ UINT32 m_nl5_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_56
+ UINT32 m_nl5_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_57
+ UINT32 m_nl5_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_58
+ UINT32 m_nl5_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl5_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_59
+ UINT32 m_nl5_rect_ltopy : 16;
+ UINT32 m_nl5_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_60
+ UINT32 m_nl5_rect_rboty : 16;
+ UINT32 m_nl5_blend_mode : 2 ;
+ UINT32 m_nl5_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_61
+ UINT32 m_nl5_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl5_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_62
+ UINT32 m_nl6_en : 1 ;
+ UINT32 m_nl6_layer_id : 4 ;
+ UINT32 m_nl6_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_63
+ UINT32 m_nl6_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_64
+ UINT32 m_nl6_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_65
+ UINT32 m_nl6_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_66
+ UINT32 m_nl6_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl6_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_67
+ UINT32 m_nl6_rect_ltopy : 16;
+ UINT32 m_nl6_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_68
+ UINT32 m_nl6_rect_rboty : 16;
+ UINT32 m_nl6_blend_mode : 2 ;
+ UINT32 m_nl6_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_69
+ UINT32 m_nl6_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl6_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_70
+ UINT32 m_nl7_en : 1 ;
+ UINT32 m_nl7_layer_id : 4 ;
+ UINT32 m_nl7_solid_en : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_cmps_reg_71
+ UINT32 m_nl7_solid_color_R : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_72
+ UINT32 m_nl7_solid_color_G : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_73
+ UINT32 m_nl7_solid_color_B : 12;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_cmps_reg_74
+ UINT32 m_nl7_color_key_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 m_nl7_rect_ltopx : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_75
+ UINT32 m_nl7_rect_ltopy : 16;
+ UINT32 m_nl7_rect_rbotx : 16;
+
+
+ //REGISTER dpu_cmps_reg_76
+ UINT32 m_nl7_rect_rboty : 16;
+ UINT32 m_nl7_blend_mode : 2 ;
+ UINT32 m_nl7_alpha_sel : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_cmps_reg_77
+ UINT32 m_nl7_alpha_factor : 8 ;
+ UINT32 : 8 ;
+ UINT32 m_nl7_layer_alpha : 8 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_cmps_reg_78
+ struct
+ {
+ UINT32 : 32;
+ }dpu_cmps_reg_78[64];
+
+ //REGISTER dpu_cmps_reg_142
+ UINT32 dbug_bus0 : 32;
+
+
+ //REGISTER dpu_cmps_reg_143
+ UINT32 dbg_bus1 : 32;
+
+
+ //REGISTER dpu_cmps_reg_144
+ UINT32 dbg_bus2 : 32;
+
+
+ //REGISTER dpu_cmps_reg_145
+ UINT32 dbg_bus3 : 32;
+
+
+ };
+
+ INT32 value32[146];
+
+}CMPS_X_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef DMA_TOP_REG_H
+#define DMA_TOP_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER DBG_EN
+ UINT32 dbg_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER DMA_ARB_OPTION
+ UINT32 img_rr_ratio : 8 ;
+ UINT32 : 4 ;
+ UINT32 round_robin_mode : 1 ;
+ UINT32 : 3 ;
+ UINT32 pixel_num_th : 6 ;
+ UINT32 : 10;
+
+
+ //REGISTER DMA_TIMEOUT_NUM
+ UINT32 rdma_timeout_limit : 16;
+ UINT32 wdma_timeout_limit : 16;
+
+
+ //REGISTER dmac0_ctrl
+ UINT32 dmac0_rstn_pwr : 1 ;
+ UINT32 dmac0_rst_req : 1 ;
+ UINT32 : 1 ;
+ UINT32 dmac0_burst_length : 3 ;
+ UINT32 dmac0_arcache : 4 ;
+ UINT32 dmac0_awcache : 4 ;
+ UINT32 dmac0_arregion : 4 ;
+ UINT32 dmac0_awregion : 4 ;
+ UINT32 : 10;
+
+
+ //REGISTER dmac1_ctrl
+ UINT32 dmac1_rstn_pwr : 1 ;
+ UINT32 dmac1_rst_req : 1 ;
+ UINT32 : 1 ;
+ UINT32 dmac1_burst_length : 3 ;
+ UINT32 dmac1_arcache : 4 ;
+ UINT32 dmac1_awcache : 4 ;
+ UINT32 dmac1_arregion : 4 ;
+ UINT32 dmac1_awregion : 4 ;
+ UINT32 : 10;
+
+
+ //REGISTER dmac2_ctrl
+ UINT32 dmac2_rstn_pwr : 1 ;
+ UINT32 dmac2_rst_req : 1 ;
+ UINT32 : 1 ;
+ UINT32 dmac2_burst_length : 3 ;
+ UINT32 dmac2_arcache : 4 ;
+ UINT32 dmac2_awcache : 4 ;
+ UINT32 dmac2_arregion : 4 ;
+ UINT32 dmac2_awregion : 4 ;
+ UINT32 : 10;
+
+
+ //REGISTER dmac3_ctrl
+ UINT32 dmac3_rstn_pwr : 1 ;
+ UINT32 dmac3_rst_req : 1 ;
+ UINT32 : 1 ;
+ UINT32 dmac3_burst_length : 3 ;
+ UINT32 dmac3_arcache : 4 ;
+ UINT32 dmac3_awcache : 4 ;
+ UINT32 dmac3_arregion : 4 ;
+ UINT32 dmac3_awregion : 4 ;
+ UINT32 : 10;
+
+
+ //REGISTER DMA_QOS
+ UINT32 online_rqos : 4 ;
+ UINT32 offline_rqos : 4 ;
+ UINT32 online_wqos : 4 ;
+ UINT32 offline_wqos : 4 ;
+ UINT32 cmdlist_rqos : 4 ;
+ UINT32 : 12;
+
+
+ //REGISTER DMAC0_OUTS_NUM
+ UINT32 dmac0_rd_outs_num : 8 ;
+ UINT32 dmac0_wr_outs_num : 8 ;
+ UINT32 : 16;
+
+
+ //REGISTER DMAC1_OUTS_NUM
+ UINT32 dmac1_rd_outs_num : 8 ;
+ UINT32 dmac1_wr_outs_num : 8 ;
+ UINT32 : 16;
+
+
+ //REGISTER DMAC2_OUTS_NUM
+ UINT32 dmac2_rd_outs_num : 8 ;
+ UINT32 dmac2_wr_outs_num : 8 ;
+ UINT32 : 16;
+
+
+ //REGISTER DMAC3_OUTS_NUM
+ UINT32 dmac3_rd_outs_num : 8 ;
+ UINT32 dmac3_wr_outs_num : 8 ;
+ UINT32 : 16;
+
+
+ //REGISTER CMDLIST0_IRQ_RAW
+ UINT32 : 6 ;
+ UINT32 cmdlist0_rdma_timeout_irq_raw : 1 ;
+ UINT32 cmdlist0_rdma_rsp_decerr_raw : 1 ;
+ UINT32 cmdlist0_rdma_rsp_slverr_raw : 1 ;
+ UINT32 cmdlist0_rdma_rsp_exok_raw : 1 ;
+ UINT32 cmdlist0_va_mismatch_raw : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB0_IRQ_RAW
+ UINT32 wb0_tlb_miss_irq_raw : 1 ;
+ UINT32 wb0_tbu_size_err_irq_raw : 1 ;
+ UINT32 wb0_mmu_rdma_timeout_raw : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_decerr_raw : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_slverr_raw : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_exok_raw : 1 ;
+ UINT32 wb0_wdma_timeout_irq_raw : 1 ;
+ UINT32 wb0_wdma_rsp_decerr_raw : 1 ;
+ UINT32 wb0_wdma_rsp_slverr_raw : 1 ;
+ UINT32 wb0_wdma_rsp_exok_raw : 1 ;
+ UINT32 wb0_va_mismatch_raw : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB1_IRQ_RAW
+ UINT32 wb1_tlb_miss_irq_raw : 1 ;
+ UINT32 wb1_tbu_size_err_irq_raw : 1 ;
+ UINT32 wb1_mmu_rdma_timeout_raw : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_decerr_raw : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_slverr_raw : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_exok_raw : 1 ;
+ UINT32 wb1_wdma_timeout_irq_raw : 1 ;
+ UINT32 wb1_wdma_rsp_decerr_raw : 1 ;
+ UINT32 wb1_wdma_rsp_slverr_raw : 1 ;
+ UINT32 wb1_wdma_rsp_exok_raw : 1 ;
+ UINT32 wb1_va_mismatch_raw : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER CMDLIST0_IRQ_MASK
+ UINT32 : 6 ;
+ UINT32 cmdlist0_rdma_timeout_irq_mask : 1 ;
+ UINT32 cmdlist0_rdma_rsp_decerr_mask : 1 ;
+ UINT32 cmdlist0_rdma_rsp_slverr_mask : 1 ;
+ UINT32 cmdlist0_rdma_rsp_exok_mask : 1 ;
+ UINT32 cmdlist0_va_mismatch_mask : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB0_IRQ_MASK
+ UINT32 wb0_tlb_miss_irq_mask : 1 ;
+ UINT32 wb0_tbu_size_err_irq_mask : 1 ;
+ UINT32 wb0_mmu_rdma_timeout_mask : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_decerr_mask : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_slverr_mask : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_exok_mask : 1 ;
+ UINT32 wb0_wdma_timeout_irq_mask : 1 ;
+ UINT32 wb0_wdma_rsp_decerr_mask : 1 ;
+ UINT32 wb0_wdma_rsp_slverr_mask : 1 ;
+ UINT32 wb0_wdma_rsp_exok_mask : 1 ;
+ UINT32 wb0_va_mismatch_mask : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB1_IRQ_MASK
+ UINT32 wb1_tlb_miss_irq_mask : 1 ;
+ UINT32 wb1_tbu_size_err_irq_mask : 1 ;
+ UINT32 wb1_mmu_rdma_timeout_mask : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_decerr_mask : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_slverr_mask : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_exok_mask : 1 ;
+ UINT32 wb1_wdma_timeout_irq_mask : 1 ;
+ UINT32 wb1_wdma_rsp_decerr_mask : 1 ;
+ UINT32 wb1_wdma_rsp_slverr_mask : 1 ;
+ UINT32 wb1_wdma_rsp_exok_mask : 1 ;
+ UINT32 wb1_va_mismatch_mask : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER CMDLIST0_IRQ_STATUS
+ UINT32 : 6 ;
+ UINT32 cmdlist0_rdma_timeout_irq_status : 1 ;
+ UINT32 cmdlist0_rdma_rsp_decerr_status : 1 ;
+ UINT32 cmdlist0_rdma_rsp_slverr_status : 1 ;
+ UINT32 cmdlist0_rdma_rsp_exok_status : 1 ;
+ UINT32 cmdlist0_va_mistach_status : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB0_IRQ_STATUS
+ UINT32 wb0_tlb_miss_irq_status : 1 ;
+ UINT32 wb0_tbu_size_err_irq_status : 1 ;
+ UINT32 wb0_mmu_rdma_timeout_status : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_decerr_status : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_slverr_status : 1 ;
+ UINT32 wb0_mmu_rdma_rsp_exok_status : 1 ;
+ UINT32 wb0_wdma_timeout_irq_status : 1 ;
+ UINT32 wb0_wdma_rsp_decerr_status : 1 ;
+ UINT32 wb0_wdma_rsp_slverr_status : 1 ;
+ UINT32 wb0_wdma_rsp_exok_status : 1 ;
+ UINT32 wb0_va_mismatch_status : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER WB1_IRQ_STATUS
+ UINT32 wb1_tlb_miss_irq_status : 1 ;
+ UINT32 wb1_tbu_size_err_irq_status : 1 ;
+ UINT32 wb1_mmu_rdma_timeout_status : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_decerr_status : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_slverr_status : 1 ;
+ UINT32 wb1_mmu_rdma_rsp_exok_status : 1 ;
+ UINT32 wb1_wdma_timeout_irq_status : 1 ;
+ UINT32 wb1_wdma_rsp_decerr_status : 1 ;
+ UINT32 wb1_wdma_rsp_slverr_status : 1 ;
+ UINT32 wb1_wdma_rsp_exok_staus : 1 ;
+ UINT32 wb1_va_mismatch_status : 1 ;
+ UINT32 : 21;
+
+
+ //REGISTER ARB_DEBUG_INFO0
+ UINT32 arb_debug_info_axi0 : 32;
+
+
+ //REGISTER ARB_DEBUG_INFO1
+ UINT32 arb_debug_info_axi1 : 32;
+
+
+ //REGISTER ARB_DEBUG_INFO2
+ UINT32 arb_debug_info_axi2 : 32;
+
+
+ //REGISTER ARB_DEBUG_INFO3
+ UINT32 arb_debug_info_axi3 : 32;
+
+
+ };
+
+ INT32 value32[25];
+
+}DMA_TOP_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef DPU_CRG_REG_H
+#define DPU_CRG_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER crg_reg_0
+ UINT32 mclk_wb_auto_en : 1 ;
+ UINT32 aclk_wb_auto_en : 1 ;
+ UINT32 aclk_rdma_auto_en : 1 ;
+ UINT32 mclk_layer_auto_en : 1 ;
+ UINT32 mclk_scl_auto_en : 1 ;
+ UINT32 mclk_cmps_auto_en : 1 ;
+ UINT32 mclk_outctl_auto_en : 1 ;
+ UINT32 dscclk_outctl_auto_en : 1 ;
+ UINT32 pixclk_outctl_auto_en : 1 ;
+ UINT32 aclk_outctl_auto_en : 1 ;
+ UINT32 aclk_cmdlist_auto_en : 1 ;
+ UINT32 pclk_cmdlist_auto_en : 1 ;
+ UINT32 aclk_dma_top_sw_en : 1 ;
+ UINT32 : 19;
+
+
+ //REGISTER crg_reg_1
+ UINT32 crg_dma_auto_en : 5 ;
+ UINT32 : 11;
+ UINT32 crg_wb_auto_en : 6 ;
+ UINT32 : 10;
+
+
+ //REGISTER crg_reg_2
+ UINT32 crg_scl_auto_en : 2 ;
+ UINT32 : 6 ;
+ UINT32 crg_pre_auto_en : 17;
+ UINT32 : 7 ;
+
+
+ //REGISTER crg_reg_3
+ UINT32 crg_outctl_auto_en : 18;
+ UINT32 : 14;
+
+
+ //REGISTER crg_reg_4
+ UINT32 crg_ctl_auto_en : 2 ;
+ UINT32 : 14;
+ UINT32 crg_cmdlist_auto_en : 2 ;
+ UINT32 : 14;
+
+
+ };
+
+ INT32 value32[5];
+
+}DPU_CRG_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef DPU_CTL_REG_H
+#define DPU_CTL_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER dpu_ctl_reg_0
+ UINT32 ctl0_nml_rch_en : 12;
+ UINT32 ctl0_nml_scl_en : 4 ;
+ UINT32 ctl0_nml_wb_en : 2 ;
+ UINT32 ctl0_nml_outctl_en : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_ctl_reg_1
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_2
+ UINT32 ctl0_nml_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_3
+ UINT32 ctl0_nml_cfg_rdy : 1 ;
+ UINT32 ctl0_sw_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_4
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_5
+ UINT32 ctl0_secu_rch_en : 12;
+ UINT32 ctl0_secu_scl_en : 4 ;
+ UINT32 ctl0_secu_wb_en : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_6
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_7
+ UINT32 ctl0_secu_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_8
+ UINT32 ctl0_secu_cfg_rdy : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_9
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_10
+ UINT32 ctl0_video_mod : 1 ;
+ UINT32 ctl0_dbg_mod : 1 ;
+ UINT32 ctl0_timing_inter0 : 4 ;
+ UINT32 : 2 ;
+ UINT32 ctl0_timing_inter1 : 4 ;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_ctl_reg_11
+ UINT32 ctl0_sw_start : 1 ;
+ UINT32 ctl0_dbg_unflow_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_12
+ UINT32 ctl1_nml_rch_en : 12;
+ UINT32 ctl1_nml_scl_en : 4 ;
+ UINT32 ctl1_nml_wb_en : 2 ;
+ UINT32 ctl1_nml_outctl_en : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_ctl_reg_13
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_14
+ UINT32 ctl1_nml_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_15
+ UINT32 ctl1_nml_cfg_rdy : 1 ;
+ UINT32 ctl1_sw_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_16
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_17
+ UINT32 ctl1_secu_rch_en : 12;
+ UINT32 ctl1_secu_scl_en : 4 ;
+ UINT32 ctl1_secu_wb_en : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_18
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_19
+ UINT32 ctl1_secu_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_20
+ UINT32 ctl1_secu_cfg_rdy : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_21
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_22
+ UINT32 ctl1_video_mod : 1 ;
+ UINT32 ctl1_dbg_mod : 1 ;
+ UINT32 ctl1_timing_inter0 : 4 ;
+ UINT32 : 2 ;
+ UINT32 ctl1_timing_inter1 : 4 ;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_ctl_reg_23
+ UINT32 ctl1_sw_start : 1 ;
+ UINT32 ctl1_dbg_unflow_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_24
+ UINT32 ctl2_nml_rch_en : 12;
+ UINT32 ctl2_nml_scl_en : 4 ;
+ UINT32 ctl2_nml_wb_en : 2 ;
+ UINT32 ctl2_nml_outctl_en : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_ctl_reg_25
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_26
+ UINT32 ctl2_nml_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_27
+ UINT32 ctl2_nml_cfg_rdy : 1 ;
+ UINT32 ctl2_sw_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_28
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_29
+ UINT32 ctl2_secu_rch_en : 12;
+ UINT32 ctl2_secu_scl_en : 4 ;
+ UINT32 ctl2_secu_wb_en : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_30
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_31
+ UINT32 ctl2_secu_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_32
+ UINT32 ctl2_secu_cfg_rdy : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_33
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_34
+ UINT32 ctl2_video_mod : 1 ;
+ UINT32 ctl2_dbg_mod : 1 ;
+ UINT32 ctl2_timing_inter0 : 4 ;
+ UINT32 : 2 ;
+ UINT32 ctl2_timing_inter1 : 4 ;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_ctl_reg_35
+ UINT32 ctl2_sw_start : 1 ;
+ UINT32 ctl2_dbg_unflow_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_36
+ UINT32 ctl3_nml_rch_en : 12;
+ UINT32 ctl3_nml_scl_en : 4 ;
+ UINT32 ctl3_nml_wb_en : 2 ;
+ UINT32 ctl3_nml_outctl_en : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_ctl_reg_37
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_38
+ UINT32 ctl3_nml_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_39
+ UINT32 ctl3_nml_cfg_rdy : 1 ;
+ UINT32 ctl3_sw_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_40
+ UINT32 ctl3_video_mod : 1 ;
+ UINT32 ctl3_dbg_mod : 1 ;
+ UINT32 ctl3_timing_inter0 : 4 ;
+ UINT32 : 2 ;
+ UINT32 ctl3_timing_inter1 : 4 ;
+ UINT32 : 20;
+
+
+ //REGISTER dpu_ctl_reg_41
+ UINT32 ctl3_sw_start : 1 ;
+ UINT32 ctl3_dbg_unflow_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_42
+ UINT32 ctl4_nml_rch_en : 12;
+ UINT32 ctl4_nml_scl_en : 4 ;
+ UINT32 ctl4_nml_wb_en : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_43
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_44
+ UINT32 ctl4_nml_cmd_updt_en : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_45
+ UINT32 ctl4_nml_cfg_rdy : 1 ;
+ UINT32 ctl4_sw_clr : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_46
+ UINT32 : 32;
+
+
+ //REGISTER dpu_ctl_reg_47
+ UINT32 ctl4_timing_inter0 : 4 ;
+ UINT32 ctl4_timing_inter1 : 4 ;
+ UINT32 : 24;
+
+
+ //REGISTER dpu_ctl_reg_48
+ UINT32 ctl_nml_scl0_layer_id : 4 ;
+ UINT32 ctl_nml_scl0_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_49
+ UINT32 ctl_nml_scl1_layer_id : 4 ;
+ UINT32 ctl_nml_scl1_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_50
+ UINT32 ctl_nml_scl2_layer_id : 4 ;
+ UINT32 ctl_nml_scl2_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_51
+ UINT32 ctl_nml_scl3_layer_id : 4 ;
+ UINT32 ctl_nml_scl3_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_52
+ UINT32 ctl_secu_scl0_layer_id : 4 ;
+ UINT32 ctl_secu_scl0_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_53
+ UINT32 ctl_secu_scl1_layer_id : 4 ;
+ UINT32 ctl_secu_scl1_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_54
+ UINT32 ctl_secu_scl2_layer_id : 4 ;
+ UINT32 ctl_secu_scl2_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_55
+ UINT32 ctl_secu_scl3_layer_id : 4 ;
+ UINT32 ctl_secu_scl3_layer_right : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER dpu_ctl_reg_56
+ UINT32 outctl_secu : 3 ;
+ UINT32 cmps_secu : 3 ;
+ UINT32 prc_curve_secu : 1 ;
+ UINT32 : 25;
+
+
+ //REGISTER dpu_ctl_reg_57
+ UINT32 ctl_rd_shadow : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER dpu_ctl_reg_58
+ UINT32 rch_conflict_ints : 12;
+ UINT32 scl_conflict_ints : 4 ;
+ UINT32 wb_timeout_ints : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_59
+ UINT32 rch_conflict_ints_msk : 12;
+ UINT32 scl_conflict_int_msk : 4 ;
+ UINT32 wb_timeout_int_msk : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_60
+ UINT32 rch_conflict_int_raw : 12;
+ UINT32 scl_conflict_int_raw : 4 ;
+ UINT32 wb_timeout_int_raw : 2 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_ctl_reg_61
+ UINT32 ctl_nml_reuse_scl0_en : 1 ;
+ UINT32 ctl_nml_cmps_scl0_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_62
+ UINT32 ctl_nml_reuse_scl1_en : 1 ;
+ UINT32 ctl_nml_cmps_scl1_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_63
+ UINT32 ctl_nml_reuse_scl2_en : 1 ;
+ UINT32 ctl_nml_cmps_scl2_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_64
+ UINT32 ctl_nml_reuse_scl3_en : 1 ;
+ UINT32 ctl_nml_cmps_scl3_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_65
+ UINT32 ctl_secu_reuse_scl0_en : 1 ;
+ UINT32 ctl_secu_cmps_scl0_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_66
+ UINT32 ctl_secu_reuse_scl1_en : 1 ;
+ UINT32 ctl_secu_cmps_scl1_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_67
+ UINT32 ctl_secu_reuse_scl2_en : 1 ;
+ UINT32 ctl_secu_cmps_scl2_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_68
+ UINT32 ctl_secu_reuse_scl3_en : 1 ;
+ UINT32 ctl_secu_cmps_scl3_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER dpu_ctl_reg_69
+ struct
+ {
+ UINT32 ctl_nml_cmdlist_rch_en : 1 ;
+ UINT32 : 31;
+ }dpu_ctl_reg_69[12];
+
+ //REGISTER dpu_ctl_reg_81
+ struct
+ {
+ UINT32 ctl_nml_cmdlist_wb_en : 1 ;
+ UINT32 : 31;
+ }dpu_ctl_reg_81[2];
+
+ //REGISTER dpu_ctl_reg_83
+ UINT32 ctl_nml_cmdlist_rch_cfg_rdy : 12;
+ UINT32 ctl_nml_cmdlist_wb_cfg_rdy : 2 ;
+ UINT32 : 18;
+
+
+ //REGISTER dpu_ctl_reg_84
+ UINT32 ctl_wb0_sel_id : 5 ;
+ UINT32 ctl_wb0_sel_right : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_ctl_reg_85
+ UINT32 ctl_wb1_sel_id : 5 ;
+ UINT32 ctl_wb1_sel_right : 1 ;
+ UINT32 : 26;
+
+
+ //REGISTER dpu_ctl_reg_86
+ UINT32 ctl_rdma_act : 12;
+ UINT32 ctl_scl_act : 4 ;
+ UINT32 ctl_layer_act : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER dpu_ctl_reg_87
+ UINT32 ctl_cmps_outctl_act : 3 ;
+ UINT32 : 5 ;
+ UINT32 ctl_wb_act : 2 ;
+ UINT32 : 6 ;
+ UINT32 ctl_wb_slice_cnt : 10;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_ctl_reg_88
+ UINT32 cmdlist_rch_act : 12;
+ UINT32 cmdlist_wb_act : 2 ;
+ UINT32 : 2 ;
+ UINT32 scene_ctl_dbg0 : 15;
+ UINT32 : 1 ;
+
+
+ //REGISTER dpu_ctl_reg_89
+ UINT32 scene_ctl_dbg1 : 15;
+ UINT32 : 1 ;
+ UINT32 scene_ctl_dbg2 : 15;
+ UINT32 : 1 ;
+
+
+ //REGISTER dpu_ctl_reg_90
+ UINT32 scene_ctl_dbg3 : 15;
+ UINT32 : 1 ;
+ UINT32 scene_ctl_dbg4 : 15;
+ UINT32 : 1 ;
+
+
+ //REGISTER dpu_ctl_reg_91
+ UINT32 rdma_clr_req_aclk : 12;
+ UINT32 wb_clr_req_aclk : 2 ;
+ UINT32 : 2 ;
+ UINT32 rdma_clr_ack_aclk : 12;
+ UINT32 wb_clr_ack_aclk : 2 ;
+ UINT32 : 2 ;
+
+
+ //REGISTER dpu_ctl_reg_92
+ UINT32 outctl_clr_req_aclk : 3 ;
+ UINT32 : 1 ;
+ UINT32 outctl_clr_ack_aclk : 3 ;
+ UINT32 : 1 ;
+ UINT32 wb_conflict_hld : 2 ;
+ UINT32 : 22;
+
+
+ //REGISTER dpu_ctl_reg_93
+ UINT32 cmdlist_clr_req_aclk : 14;
+ UINT32 : 2 ;
+ UINT32 cmdlist_clr_ack_aclk : 14;
+ UINT32 : 2 ;
+
+
+ };
+
+ INT32 value32[94];
+
+}DPU_CTL_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef DPU_INTP_REG_H
+#define DPU_INTP_REG_H
+
+
+#define DPU_INT_CMDLIST_CH_FRM_CFG_DONE_MASK (0x3fff)
+#define DPU_INT_CMDLIST_CH_FRM_CFG_DONE (DPU_INT_CMDLIST_CH_FRM_CFG_DONE_MASK << 12)
+#define DPU_INT_WB_OVFLOW_MASK (0x3)
+#define DPU_INT_WB_OVFLOW (DPU_INT_WB_OVFLOW_MASK << 10)
+#define DPU_INT_FRM_TIMING_UNFLOW BIT(9)
+#define DPU_INT_WB_DONE_MASK (0x3)
+#define DPU_INT_WB_DONE (DPU_INT_WB_DONE_MASK << 7)
+#define DPU_INT_CURVE_DONE BIT(6)
+#define DPU_INT_HIST_DONE BIT(5)
+#define DPU_INT_CFG_RDY_CLR BIT(4)
+#define DPU_INT_FRM_TIMING_CFG_LINE BIT(3)
+#define DPU_INT_FRM_TIMING_CFG_EOF BIT(2)
+#define DPU_INT_FRM_TIMING_EOF BIT(1)
+#define DPU_INT_FRM_TIMING_VSYNC BIT(0)
+
+#define DPU_REST_INT_BITS (DPU_INT_FRM_TIMING_CFG_EOF | \
+ DPU_INT_FRM_TIMING_CFG_LINE | \
+ DPU_INT_HIST_DONE | \
+ DPU_INT_CURVE_DONE | \
+ DPU_INT_CMDLIST_CH_FRM_CFG_DONE)
+
+typedef union
+{
+ struct
+ {
+ //REGISTER dpu_int_reg_0
+ UINT32 onl0_nml_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl0_nml_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl0_nml_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl0_nml_hist_done_int_msk : 1 ;
+ UINT32 onl0_nml_curve_done_int_msk : 1 ;
+ UINT32 onl0_nml_wb_done_int_msk : 2 ;
+ UINT32 onl0_nml_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl0_nml_wb_ovflow_int_msk : 2 ;
+ UINT32 onl0_nml_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_1
+ UINT32 onl0_nml_dma_dbg_int_msk : 16;
+ UINT32 onl0_nml_outctl_dbg_int_msk : 1 ;
+ UINT32 onl0_nml_ctl_dbg_int_msk : 1 ;
+ UINT32 onl0_nml_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_2
+ UINT32 onl1_nml_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl1_nml_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl1_nml_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl1_nml_hist_done_int_msk : 1 ;
+ UINT32 onl1_nml_curve_done_int_msk : 1 ;
+ UINT32 onl1_nml_wb_done_int_msk : 2 ;
+ UINT32 onl1_nml_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl1_nml_wb_ovflow_int_msk : 2 ;
+ UINT32 onl1_nml_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_3
+ UINT32 onl1_nml_dma_dbg_int_msk : 16;
+ UINT32 onl1_nml_outctl_dbg_int_msk : 1 ;
+ UINT32 onl1_nml_ctl_dbg_int_msk : 1 ;
+ UINT32 onl1_nml_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_4
+ UINT32 onl2_nml_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl2_nml_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl2_nml_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl2_nml_hist_done_int_msk : 1 ;
+ UINT32 onl2_nml_curve_done_int_msk : 1 ;
+ UINT32 onl2_nml_wb_done_int_msk : 2 ;
+ UINT32 onl2_nml_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl2_nml_wb_ovflow_int_msk : 2 ;
+ UINT32 onl2_nml_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_5
+ UINT32 onl2_nml_dma_dbg_int_msk : 16;
+ UINT32 onl2_nml_outctl_dbg_int_msk : 1 ;
+ UINT32 onl2_nml_ctl_dbg_int_msk : 1 ;
+ UINT32 onl2_nml_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_6
+ UINT32 offl0_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 offl0_wb_frm_done_int_msk : 2 ;
+ UINT32 offl0_wb_slice_done_int_msk : 2 ;
+ UINT32 offl0_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_7
+ UINT32 offl0_nml_dma_dbg_int_msk : 16;
+ UINT32 offl0_nml_ctl_dbg_int_msk : 1 ;
+ UINT32 offl0_nml_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_8
+ UINT32 offl1_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 offl1_wb_frm_done_int_msk : 2 ;
+ UINT32 offl1_wb_slice_done_int_msk : 2 ;
+ UINT32 offl1_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_9
+ UINT32 offl1_nml_dma_dbg_int_msk : 16;
+ UINT32 offl1_nml_ctl_dbg_int_msk : 1 ;
+ UINT32 offl1_nml_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_10
+ UINT32 onl0_nml_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl0_nml_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl0_nml_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl0_nml_hist_done_int_sts : 1 ;
+ UINT32 onl0_nml_curve_done_int_sts : 1 ;
+ UINT32 onl0_nml_wb_done_int_sts : 2 ;
+ UINT32 onl0_nml_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl0_nml_wb_ovflow_int_sts : 2 ;
+ UINT32 onl0_nml_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_11
+ UINT32 onl0_nml_dma_dbg_int_sts : 16;
+ UINT32 onl0_nml_outctl_dbg_int_sts : 1 ;
+ UINT32 onl0_nml_ctl_dbg_int_sts : 1 ;
+ UINT32 onl0_nml_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_12
+ UINT32 onl1_nml_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl1_nml_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl1_nml_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl1_nml_hist_done_int_sts : 1 ;
+ UINT32 onl1_nml_curve_done_int_sts : 1 ;
+ UINT32 onl1_nml_wb_done_int_sts : 2 ;
+ UINT32 onl1_nml_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl1_nml_wb_ovflow_int_sts : 2 ;
+ UINT32 onl1_nml_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_13
+ UINT32 onl1_nml_dma_dbg_int_sts : 16;
+ UINT32 onl1_nml_outctl_dbg_int_sts : 1 ;
+ UINT32 onl1_nml_ctl_dbg_int_sts : 1 ;
+ UINT32 onl1_nml_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_14
+ UINT32 onl2_nml_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl2_nml_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl2_nml_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl2_nml_hist_done_int_sts : 1 ;
+ UINT32 onl2_nml_curve_done_int_sts : 1 ;
+ UINT32 onl2_nml_wb_done_int_sts : 2 ;
+ UINT32 onl2_nml_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl2_nml_wb_ovflow_int_sts : 2 ;
+ UINT32 onl2_nml_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_15
+ UINT32 onl2_nml_dma_dbg_int_sts : 16;
+ UINT32 onl2_nml_outctl_dbg_int_sts : 1 ;
+ UINT32 onl2_nml_ctl_dbg_int_sts : 1 ;
+ UINT32 onl2_nml_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_16
+ UINT32 offl0_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 offl0_wb_frm_done_int_sts : 2 ;
+ UINT32 offl0_wb_slice_done_int_sts : 2 ;
+ UINT32 offl0_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_17
+ UINT32 offl0_nml_dma_dbg_int_sts : 16;
+ UINT32 offl0_nml_ctl_dbg_int_sts : 1 ;
+ UINT32 offl0_nml_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_18
+ UINT32 offl1_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 offl1_wb_frm_done_int_sts : 2 ;
+ UINT32 offl1_wb_slice_done_int_sts : 2 ;
+ UINT32 offl1_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_19
+ UINT32 offl1_nml_dma_dbg_int_sts : 16;
+ UINT32 offl1_nml_ctl_dbg_int_sts : 1 ;
+ UINT32 offl1_nml_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_20
+ UINT32 onl0_nml_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl0_nml_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl0_nml_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl0_nml_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl0_nml_hist_done_int_raw : 1 ;
+ UINT32 onl0_nml_curve_done_int_raw : 1 ;
+ UINT32 onl0_nml_wb_done_int_raw : 2 ;
+ UINT32 onl0_nml_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl0_nml_wb_ovflow_int_raw : 2 ;
+ UINT32 onl0_nml_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_21
+ UINT32 onl0_nml_dma_dbg_int_raw : 16;
+ UINT32 onl0_nml_outctl_dbg_int_raw : 1 ;
+ UINT32 onl0_nml_ctl_dbg_int_raw : 1 ;
+ UINT32 onl0_nml_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_22
+ UINT32 onl1_nml_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl1_nml_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl1_nml_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl1_nml_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl1_nml_hist_done_int_raw : 1 ;
+ UINT32 onl1_nml_curve_done_int_raw : 1 ;
+ UINT32 onl1_nml_wb_done_int_raw : 2 ;
+ UINT32 onl1_nml_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl1_nml_wb_ovflow_int_raw : 2 ;
+ UINT32 onl1_nml_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_23
+ UINT32 onl1_nml_dma_dbg_int_raw : 16;
+ UINT32 onl1_nml_outctl_dbg_int_raw : 1 ;
+ UINT32 onl1_nml_ctl_dbg_int_raw : 1 ;
+ UINT32 onl1_nml_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_24
+ UINT32 onl2_nml_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl2_nml_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl2_nml_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl2_nml_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl2_nml_hist_done_int_raw : 1 ;
+ UINT32 onl2_nml_curve_done_int_raw : 1 ;
+ UINT32 onl2_nml_wb_done_int_raw : 2 ;
+ UINT32 onl2_nml_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl2_nml_wb_ovflow_int_raw : 2 ;
+ UINT32 onl2_nml_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_25
+ UINT32 onl2_nml_dma_dbg_int_raw : 16;
+ UINT32 onl2_nml_outctl_dbg_int_raw : 1 ;
+ UINT32 onl2_nml_ctl_dbg_int_raw : 1 ;
+ UINT32 onl2_nml_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_26
+ UINT32 offl0_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 offl0_wb_frm_done_int_raw : 2 ;
+ UINT32 offl0_wb_slice_done_int_raw : 2 ;
+ UINT32 offl0_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_27
+ UINT32 offl0_nml_dma_dbg_int_raw : 16;
+ UINT32 offl0_nml_ctl_dbg_int_raw : 1 ;
+ UINT32 offl0_nml_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_28
+ UINT32 offl1_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 offl1_wb_frm_done_int_raw : 2 ;
+ UINT32 offl1_wb_slice_done_int_raw : 2 ;
+ UINT32 offl1_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_29
+ UINT32 offl1_nml_dma_dbg_int_raw : 16;
+ UINT32 offl1_nml_ctl_dbg_int_raw : 1 ;
+ UINT32 offl1_nml_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 14;
+
+
+ //REGISTER dpu_int_reg_30
+ struct
+ {
+ UINT32 : 32;
+ }dpu_int_reg_30[10];
+
+ //REGISTER dpu_int_reg_40
+ UINT32 onl0_secu_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl0_secu_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl0_secu_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl0_secu_hist_done_int_msk : 1 ;
+ UINT32 onl0_secu_curve_done_int_msk : 1 ;
+ UINT32 onl0_secu_wb_done_int_msk : 2 ;
+ UINT32 onl0_secu_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl0_secu_wb_ovflow_int_msk : 2 ;
+ UINT32 onl0_secu_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_41
+ UINT32 onl0_secu_dma_dbg_int_msk : 16;
+ UINT32 onl0_secu_outctl_dbg_int_msk : 1 ;
+ UINT32 onl0_secu_ctl_dbg_int_msk : 1 ;
+ UINT32 onl0_secu_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_42
+ UINT32 onl1_secu_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl1_secu_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl1_secu_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl1_secu_hist_done_int_msk : 1 ;
+ UINT32 onl1_secu_curve_done_int_msk : 1 ;
+ UINT32 onl1_secu_wb_done_int_msk : 2 ;
+ UINT32 onl1_secu_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl1_secu_wb_ovflow_int_msk : 2 ;
+ UINT32 onl1_secu_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_43
+ UINT32 onl1_secu_dma_dbg_int_msk : 16;
+ UINT32 onl1_secu_outctl_dbg_int_msk : 1 ;
+ UINT32 onl1_secu_ctl_dbg_int_msk : 1 ;
+ UINT32 onl1_secu_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_44
+ UINT32 onl2_secu_frm_timing_vsync_int_msk : 1 ;
+ UINT32 onl2_secu_frm_timing_eof_int_msk : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_eof_int_msk : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_line_int_msk : 1 ;
+ UINT32 onl2_secu_cfg_rdy_clr_int_msk : 1 ;
+ UINT32 onl2_secu_hist_done_int_msk : 1 ;
+ UINT32 onl2_secu_curve_done_int_msk : 1 ;
+ UINT32 onl2_secu_wb_done_int_msk : 2 ;
+ UINT32 onl2_secu_frm_timing_unflow_int_msk : 1 ;
+ UINT32 onl2_secu_wb_ovflow_int_msk : 2 ;
+ UINT32 onl2_secu_cmdlist_ch_frm_cfg_done_int_msk : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_45
+ UINT32 onl2_secu_dma_dbg_int_msk : 16;
+ UINT32 onl2_secu_outctl_dbg_int_msk : 1 ;
+ UINT32 onl2_secu_ctl_dbg_int_msk : 1 ;
+ UINT32 onl2_secu_cmdlist_dbg_int_msk : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_46
+ UINT32 onl0_secu_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl0_secu_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl0_secu_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl0_secu_hist_done_int_sts : 1 ;
+ UINT32 onl0_secu_curve_done_int_sts : 1 ;
+ UINT32 onl0_secu_wb_done_int_sts : 2 ;
+ UINT32 onl0_secu_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl0_secu_wb_ovflow_int_sts : 2 ;
+ UINT32 onl0_secu_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_47
+ UINT32 onl0_secu_dma_dbg_int_sts : 16;
+ UINT32 onl0_secu_outctl_dbg_int_sts : 1 ;
+ UINT32 onl0_secu_ctl_dbg_int_sts : 1 ;
+ UINT32 onl0_secu_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_48
+ UINT32 onl1_secu_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl1_secu_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl1_secu_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl1_secu_hist_done_int_sts : 1 ;
+ UINT32 onl1_secu_curve_done_int_sts : 1 ;
+ UINT32 onl1_secu_wb_done_int_sts : 2 ;
+ UINT32 onl1_secu_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl1_secu_wb_ovflow_int_sts : 2 ;
+ UINT32 onl1_secu_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_49
+ UINT32 onl1_secu_dma_dbg_int_sts : 16;
+ UINT32 onl1_secu_outctl_dbg_int_sts : 1 ;
+ UINT32 onl1_secu_ctl_dbg_int_sts : 1 ;
+ UINT32 onl1_secu_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_50
+ UINT32 onl2_secu_frm_timing_vsync_int_sts : 1 ;
+ UINT32 onl2_secu_frm_timing_eof_int_sts : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_eof_int_sts : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_line_int_sts : 1 ;
+ UINT32 onl2_secu_cfg_rdy_clr_int_sts : 1 ;
+ UINT32 onl2_secu_hist_done_int_sts : 1 ;
+ UINT32 onl2_secu_curve_done_int_sts : 1 ;
+ UINT32 onl2_secu_wb_done_int_sts : 2 ;
+ UINT32 onl2_secu_frm_timing_unflow_int_sts : 1 ;
+ UINT32 onl2_secu_wb_ovflow_int_sts : 2 ;
+ UINT32 onl2_secu_cmdlist_ch_frm_cfg_done_int_sts : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_51
+ UINT32 onl2_secu_dma_dbg_int_sts : 16;
+ UINT32 onl2_secu_outctl_dbg_int_sts : 1 ;
+ UINT32 onl2_secu_ctl_dbg_int_sts : 1 ;
+ UINT32 onl2_secu_cmdlist_dbg_int_sts : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_52
+ UINT32 onl0_secu_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl0_secu_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl0_secu_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl0_secu_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl0_secu_hist_done_int_raw : 1 ;
+ UINT32 onl0_secu_curve_done_int_raw : 1 ;
+ UINT32 onl0_secu_wb_done_int_raw : 2 ;
+ UINT32 onl0_secu_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl0_secu_wb_ovflow_int_raw : 2 ;
+ UINT32 onl0_secu_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_53
+ UINT32 onl0_secu_dma_dbg_int_raw : 16;
+ UINT32 onl0_secu_outctl_dbg_int_raw : 1 ;
+ UINT32 onl0_secu_ctl_dbg_int_raw : 1 ;
+ UINT32 onl0_secu_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_54
+ UINT32 onl1_secu_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl1_secu_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl1_secu_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl1_secu_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl1_secu_hist_done_int_raw : 1 ;
+ UINT32 onl1_secu_curve_done_int_raw : 1 ;
+ UINT32 onl1_secu_wb_done_int_raw : 2 ;
+ UINT32 onl1_secu_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl1_secu_wb_ovflow_int_raw : 2 ;
+ UINT32 onl1_secu_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_55
+ UINT32 onl1_secu_dma_dbg_int_raw : 16;
+ UINT32 onl1_secu_outctl_dbg_int_raw : 1 ;
+ UINT32 onl1_secu_ctl_dbg_int_raw : 1 ;
+ UINT32 onl1_secu_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ //REGISTER dpu_int_reg_56
+ UINT32 onl2_secu_frm_timing_vsync_int_raw : 1 ;
+ UINT32 onl2_secu_frm_timing_eof_int_raw : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_eof_int_raw : 1 ;
+ UINT32 onl2_secu_frm_timing_cfg_line_int_raw : 1 ;
+ UINT32 onl2_secu_cfg_rdy_clr_int_raw : 1 ;
+ UINT32 onl2_secu_hist_done_int_raw : 1 ;
+ UINT32 onl2_secu_curve_done_int_raw : 1 ;
+ UINT32 onl2_secu_wb_done_int_raw : 2 ;
+ UINT32 onl2_secu_frm_timing_unflow_int_raw : 1 ;
+ UINT32 onl2_secu_wb_ovflow_int_raw : 2 ;
+ UINT32 onl2_secu_cmdlist_ch_frm_cfg_done_int_raw : 14;
+ UINT32 : 6 ;
+
+
+ //REGISTER dpu_int_reg_57
+ UINT32 onl2_secu_dma_dbg_int_raw : 16;
+ UINT32 onl2_secu_outctl_dbg_int_raw : 1 ;
+ UINT32 onl2_secu_ctl_dbg_int_raw : 1 ;
+ UINT32 onl2_secu_cmdlist_dbg_int_raw : 1 ;
+ UINT32 : 13;
+
+
+ } b;
+
+ struct
+ {
+ UINT32 dpu_int_reg_0;
+ UINT32 dpu_int_reg_1;
+ UINT32 dpu_int_reg_2;
+ UINT32 dpu_int_reg_3;
+ UINT32 dpu_int_reg_4;
+ UINT32 dpu_int_reg_5;
+ UINT32 dpu_int_reg_6;
+ UINT32 dpu_int_reg_7;
+ UINT32 dpu_int_reg_8;
+ UINT32 dpu_int_reg_9;
+ UINT32 dpu_int_reg_10;
+ UINT32 dpu_int_reg_11;
+ UINT32 dpu_int_reg_12;
+ UINT32 dpu_int_reg_13;
+ UINT32 dpu_int_reg_14;
+ UINT32 dpu_int_reg_15;
+ UINT32 dpu_int_reg_16;
+ UINT32 dpu_int_reg_17;
+ UINT32 dpu_int_reg_18;
+ UINT32 dpu_int_reg_19;
+ UINT32 dpu_int_reg_20;
+ UINT32 dpu_int_reg_21;
+ UINT32 dpu_int_reg_22;
+ UINT32 dpu_int_reg_23;
+ UINT32 dpu_int_reg_24;
+ UINT32 dpu_int_reg_25;
+ UINT32 dpu_int_reg_26;
+ UINT32 dpu_int_reg_27;
+ UINT32 dpu_int_reg_28;
+ UINT32 dpu_int_reg_29;
+ UINT32 dpu_int_reg_30;
+ UINT32 dpu_int_reg_31;
+ UINT32 dpu_int_reg_32;
+ UINT32 dpu_int_reg_33;
+ UINT32 dpu_int_reg_34;
+ UINT32 dpu_int_reg_35;
+ UINT32 dpu_int_reg_36;
+ UINT32 dpu_int_reg_37;
+ UINT32 dpu_int_reg_38;
+ UINT32 dpu_int_reg_39;
+ UINT32 dpu_int_reg_40;
+ UINT32 dpu_int_reg_41;
+ UINT32 dpu_int_reg_42;
+ UINT32 dpu_int_reg_43;
+ UINT32 dpu_int_reg_44;
+ UINT32 dpu_int_reg_45;
+ UINT32 dpu_int_reg_46;
+ UINT32 dpu_int_reg_47;
+ UINT32 dpu_int_reg_48;
+ UINT32 dpu_int_reg_49;
+ UINT32 dpu_int_reg_50;
+ UINT32 dpu_int_reg_51;
+ UINT32 dpu_int_reg_52;
+ UINT32 dpu_int_reg_53;
+ UINT32 dpu_int_reg_54;
+ UINT32 dpu_int_reg_55;
+ UINT32 dpu_int_reg_56;
+ UINT32 dpu_int_reg_57;
+ } v;
+
+}DPU_INTP_REG;
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef DPU_TOP_REG_H
+#define DPU_TOP_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER dpu_top_reg_0
+ UINT32 Minor_number : 8 ;
+ UINT32 Major_number : 8 ;
+ UINT32 Product_ID : 16;
+
+
+ //REGISTER dpu_top_reg_1
+ struct
+ {
+ UINT32 : 32;
+ }dpu_top_reg_1[213];
+
+ //REGISTER dpu_top_reg_214
+ UINT32 dma0_to_layer0_valid : 1 ;
+ UINT32 layer0_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer1_valid : 1 ;
+ UINT32 layer1_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer2_valid : 1 ;
+ UINT32 layer2_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer3_valid : 1 ;
+ UINT32 layer3_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer4_valid : 1 ;
+ UINT32 layer4_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer5_valid : 1 ;
+ UINT32 layer5_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer6_valid : 1 ;
+ UINT32 layer6_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer7_valid : 1 ;
+ UINT32 layer7_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer8_valid : 1 ;
+ UINT32 layer8_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer9_valid : 1 ;
+ UINT32 layer9_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer10_valid : 1 ;
+ UINT32 layer10_to_dma0_ready : 1 ;
+ UINT32 dma0_to_layer11_valid : 1 ;
+ UINT32 layer11_to_dma0_ready : 1 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_top_reg_215
+ UINT32 dma1_to_layer0_valid : 1 ;
+ UINT32 layer0_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer1_valid : 1 ;
+ UINT32 layer1_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer2_valid : 1 ;
+ UINT32 layer2_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer3_valid : 1 ;
+ UINT32 layer3_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer4_valid : 1 ;
+ UINT32 layer4_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer5_valid : 1 ;
+ UINT32 layer5_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer6_valid : 1 ;
+ UINT32 layer6_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer7_valid : 1 ;
+ UINT32 layer7_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer8_valid : 1 ;
+ UINT32 layer8_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer9_valid : 1 ;
+ UINT32 layer9_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer10_valid : 1 ;
+ UINT32 layer10_to_dma1_ready : 1 ;
+ UINT32 dma1_to_layer11_valid : 1 ;
+ UINT32 layer11_to_dma1_ready : 1 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER dpu_top_reg_216
+ UINT32 core0_onl_pre_to_post_valid : 1 ;
+ UINT32 core0_onl_post_to_pre_ready : 1 ;
+ UINT32 core1_onl_pre_to_post_valid : 1 ;
+ UINT32 core1_onl_post_to_pre_ready : 1 ;
+ UINT32 core2_cmb_pre_to_post_valid : 1 ;
+ UINT32 core2_cmb_post_to_pre_ready : 1 ;
+ UINT32 core3_cmb_pre_to_post_valid : 1 ;
+ UINT32 core3_cmb_post_to_pre_ready : 1 ;
+ UINT32 : 8 ;
+ UINT32 prepipe_wb0_valid : 1 ;
+ UINT32 wb0_prepipe_ready : 1 ;
+ UINT32 prepipe_wb1_valid : 1 ;
+ UINT32 wb1_prepipe_ready : 1 ;
+ UINT32 : 12;
+
+
+ //REGISTER dpu_top_reg_217
+ UINT32 prepipe_to_scale0_valid : 1 ;
+ UINT32 scale0_to_prepipe_ready : 1 ;
+ UINT32 prepipe_to_scale1_valid : 1 ;
+ UINT32 scale1_to_prepipe_ready : 1 ;
+ UINT32 scale0_to_prepipe_valid : 1 ;
+ UINT32 prepipe_to_scale0_ready : 1 ;
+ UINT32 scale1_to_prepipe_valid : 1 ;
+ UINT32 prepipe_to_scale1_ready : 1 ;
+ UINT32 postpipe_to_scale0_valid : 1 ;
+ UINT32 scale0_to_postpipe_ready : 1 ;
+ UINT32 postpipe_to_scale1_valid : 1 ;
+ UINT32 scale1_to_postpipe_ready : 1 ;
+ UINT32 scale0_to_post_valid : 1 ;
+ UINT32 postpipe_to_scale0_ready : 1 ;
+ UINT32 scale1_to_postpipe_valid : 1 ;
+ UINT32 postpipe_to_scale1_ready : 1 ;
+ UINT32 : 16;
+
+
+ };
+
+ INT32 value32[218];
+
+}DPU_TOP_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef MMU_REG_H
+#define MMU_REG_H
+
+typedef union
+{
+ struct
+ {
+ struct
+ {
+ //REGISTER TBU_Timelimit
+ UINT32 rdma_timelimit : 16;
+ UINT32 mmu_cg_en : 1 ;
+ UINT32 : 15;
+
+
+ //REGISTER TBU_AXI_PORT_SEL
+ UINT32 axi_port_sel0 : 2 ;
+ UINT32 axi_port_sel1 : 2 ;
+ UINT32 axi_port_sel2 : 2 ;
+ UINT32 axi_port_sel3 : 2 ;
+ UINT32 : 24;
+
+
+ //REGISTER TLB_Miss_stat
+ UINT32 tlb_miss_num_clr : 1 ;
+ UINT32 tlb_miss_num_sel : 7 ;
+ UINT32 : 8 ;
+ UINT32 tlb_miss_num : 16;
+
+
+ //REGISTER MMU_Dmac0_Reg
+ UINT32 : 4 ;
+ UINT32 cfg_dmac0_arcache : 4 ;
+ UINT32 cfg_dmac0_arregion : 4 ;
+ UINT32 cfg_dmac0_aruser : 4 ;
+ UINT32 cfg_dmac0_rd_outs_num : 8 ;
+ UINT32 cfg_dmac0_axi_burst : 3 ;
+ UINT32 : 5 ;
+
+
+ //REGISTER MMU_Dmac1_Reg
+ UINT32 : 4 ;
+ UINT32 cfg_dmac1_arcache : 4 ;
+ UINT32 cfg_dmac1_arregion : 4 ;
+ UINT32 cfg_dmac1_aruser : 4 ;
+ UINT32 cfg_dmac1_rd_outs_num : 8 ;
+ UINT32 cfg_dmac1_axi_burst : 3 ;
+ UINT32 : 5 ;
+
+
+ //REGISTER MMU_Dmac2_Reg
+ UINT32 : 4 ;
+ UINT32 cfg_dmac2_arcache : 4 ;
+ UINT32 cfg_dmac2_arregion : 4 ;
+ UINT32 cfg_dmac2_aruser : 4 ;
+ UINT32 cfg_dmac2_rd_outs_num : 8 ;
+ UINT32 cfg_dmac2_axi_burst : 3 ;
+ UINT32 : 5 ;
+
+
+ //REGISTER MMU_Dmac3_Reg
+ UINT32 : 4 ;
+ UINT32 cfg_dmac3_arcache : 4 ;
+ UINT32 cfg_dmac3_arregion : 4 ;
+ UINT32 cfg_dmac3_aruser : 4 ;
+ UINT32 cfg_dmac3_rd_outs_num : 8 ;
+ UINT32 cfg_dmac3_axi_burst : 3 ;
+ UINT32 : 5 ;
+
+
+ //REGISTER MMU_axi0_ar_debug_Reg
+ UINT32 axi0_ar_debug : 32;
+
+
+ //REGISTER MMU_axi0_aw_debug_Reg
+ UINT32 axi0_aw_debug : 32;
+
+
+ //REGISTER MMU_axi1_ar_debug_Reg
+ UINT32 axi1_ar_debug : 32;
+
+
+ //REGISTER MMU_axi1_aw_debug_Reg
+ UINT32 axi1_aw_debug : 32;
+
+
+ //REGISTER MMU_axi2_ar_debug_Reg
+ UINT32 axi2_ar_debug : 32;
+
+
+ //REGISTER MMU_axi2_aw_debug_Reg
+ UINT32 axi2_aw_debug : 32;
+
+
+ //REGISTER MMU_axi3_ar_debug_Reg
+ UINT32 axi3_ar_debug : 32;
+
+
+ //REGISTER MMU_axi3_aw_debug_Reg
+ UINT32 axi3_aw_debug : 32;
+
+
+ //REGISTER TLB_CMD_NUM
+ UINT32 tlb_cmd_num_sel : 7 ;
+ UINT32 : 9 ;
+ UINT32 tlb_cmd_num : 16;
+
+
+ //REGISTER TLB_CMD_NUM_TOTAL
+ UINT32 tlb_cmd_num_total : 32;
+
+
+ //REGISTER TLB_WAIT_CYCLE
+ UINT32 tlb_wait_cycle_sel : 7 ;
+ UINT32 : 9 ;
+ UINT32 tlb_wait_cycle : 16;
+
+
+ //REGISTER TLB_WAIT_CYCLE_TOTAL
+ UINT32 tlb_wait_cycle_total : 32;
+
+
+ //REGISTER TLB_MISS_NUM_TOTAL
+ UINT32 tlb_miss_num_total : 32;
+
+
+ struct {
+ UINT32 : 32;
+ } reserve[44];
+
+ struct
+ {
+ //REGISTER TBU_Ctrl
+ UINT32 tbu_en : 1 ;
+ UINT32 tbu_fbc_mode : 1 ;
+ UINT32 tbu_plane_num : 2 ;
+ UINT32 tbu_burst_limit_en : 1 ;
+ UINT32 tlb_fetch_active_en : 1 ;
+ UINT32 : 2 ;
+ UINT32 tbu_qos : 4 ;
+ UINT32 : 20;
+
+
+ //REGISTER TBU_Base_Addr0_Low
+ UINT32 tbu_base_addr0_low : 32;
+
+
+ //REGISTER TBU_Base_Addr0_High
+ UINT32 tbu_base_addr0_high : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER TBU_Base_Addr1_Low
+ UINT32 tbu_base_addr1_low : 32;
+
+
+ //REGISTER TBU_Base_Addr1_High
+ UINT32 tbu_base_addr1_high : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER TBU_Base_Addr2_Low
+ UINT32 tbu_base_addr2_low : 32;
+
+
+ //REGISTER TBU_Base_Addr2_High
+ UINT32 tbu_base_addr2_high : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER TBU_VA0
+ UINT32 tbu_va0 : 22;
+ UINT32 : 10;
+
+
+ //REGISTER TBU_VA1
+ UINT32 tbu_va1 : 22;
+ UINT32 : 10;
+
+
+ //REGISTER TBU_VA2
+ UINT32 tbu_va2 : 22;
+ UINT32 : 10;
+
+
+ //REGISTER TBU_SIZE0
+ UINT32 tbu_size0 : 16;
+ UINT32 : 16;
+
+
+ //REGISTER TBU_SIZE1
+ UINT32 tbu_size1 : 16;
+ UINT32 : 16;
+
+
+ //REGISTER TBU_SIZE2
+ UINT32 tbu_size2 : 16;
+ UINT32 : 16;
+
+ struct {
+ UINT32 : 32;
+ } reserve[3];
+
+ }TBU[9];
+
+ };
+
+ INT32 value32[208];
+ } b;
+
+ struct
+ {
+ //REGISTER TBU_Timelimit
+ UINT32 TBU_Timelimit;
+
+
+ //REGISTER TBU_AXI_PORT_SEL
+ UINT32 TBU_AXI_PORT_SEL;
+
+
+ //REGISTER TLB_Miss_stat
+ UINT32 TLB_Miss_stat;
+
+
+ //REGISTER MMU_Dmac0_Reg
+ UINT32 MMU_Dmac0_Reg;
+
+
+ //REGISTER MMU_Dmac1_Reg
+ UINT32 MMU_Dmac1_Reg;
+
+
+ //REGISTER MMU_Dmac2_Reg
+ UINT32 MMU_Dmac2_Reg;
+
+
+ //REGISTER MMU_Dmac3_Reg
+ UINT32 MMU_Dmac3_Reg;
+
+ //REGISTER MMU_axi0_ar_debug_Reg
+ UINT32 MMU_axi0_ar_debug_Reg;
+
+
+ //REGISTER MMU_axi0_aw_debug_Reg
+ UINT32 MMU_axi0_aw_debug_Reg;
+
+
+ //REGISTER MMU_axi1_ar_debug_Reg
+ UINT32 MMU_axi1_ar_debug_Reg;
+
+
+ //REGISTER MMU_axi1_aw_debug_Reg
+ UINT32 MMU_axi1_aw_debug_Reg;
+
+
+ //REGISTER MMU_axi2_ar_debug_Reg
+ UINT32 axi2_ar_debug;
+
+
+ //REGISTER MMU_axi2_aw_debug_Reg
+ UINT32 MMU_axi2_aw_debug_Reg;
+
+
+ //REGISTER MMU_axi3_ar_debug_Reg
+ UINT32 MMU_axi3_ar_debug_Reg;
+
+
+ //REGISTER MMU_axi3_aw_debug_Reg
+ UINT32 axi3_aw_debug;
+
+
+ //REGISTER TLB_CMD_NUM
+ UINT32 TLB_CMD_NUM;
+
+
+ //REGISTER TLB_CMD_NUM_TOTAL
+ UINT32 TLB_CMD_NUM_TOTAL;
+
+
+ //REGISTER TLB_WAIT_CYCLE
+ UINT32 TLB_WAIT_CYCLE;
+
+
+ //REGISTER TLB_WAIT_CYCLE_TOTAL
+ UINT32 TLB_WAIT_CYCLE_TOTAL;
+
+
+ //REGISTER TLB_MISS_NUM_TOTAL
+ UINT32 TLB_MISS_NUM_TOTAL;
+
+ //Reserved
+ struct {
+ UINT32 RESERVED;
+ } reserve[44];
+
+ struct
+ {
+ //REGISTER TBU_Ctrl
+ UINT32 TBU_Ctrl;
+
+
+ //REGISTER TBU_Base_Addr0_Low
+ UINT32 TBU_Base_Addr0_Low;
+
+
+ //REGISTER TBU_Base_Addr0_High
+ UINT32 TBU_Base_Addr0_High;
+
+
+ //REGISTER TBU_Base_Addr1_Low
+ UINT32 TBU_Base_Addr1_Low;
+
+
+ //REGISTER TBU_Base_Addr1_High
+ UINT32 TBU_Base_Addr1_High;
+
+
+ //REGISTER TBU_Base_Addr2_Low
+ UINT32 TBU_Base_Addr2_Low;
+
+
+ //REGISTER TBU_Base_Addr2_High
+ UINT32 TBU_Base_Addr2_High;
+
+
+ //REGISTER TBU_VA0
+ UINT32 TBU_VA0;
+
+
+ UINT32 TBU_VA1;
+
+
+ //REGISTER TBU_VA2
+ UINT32 TBU_VA2;
+
+
+ //REGISTER TBU_SIZE0
+ UINT32 TBU_SIZE0;
+
+
+ //REGISTER TBU_SIZE1
+ UINT32 TBU_SIZE1;
+
+
+ //REGISTER TBU_SIZE2
+ UINT32 TBU_SIZE2;
+
+ struct {
+ UINT32 : 32;
+ } reserve[3];
+
+ }TBU[9];
+
+ } v;
+
+}MMU_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef OUTCTRL_PROC_X_REG_H
+#define OUTCTRL_PROC_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER Post_proc_reg_0
+ UINT32 m_npost_proc_en : 1 ;
+ UINT32 m_ngain_to_full_en : 1 ;
+ UINT32 m_nmatrix_en : 1 ;
+ UINT32 m_nendmatrix_en : 1 ;
+ UINT32 m_nfront_tmootf_en : 1 ;
+ UINT32 m_nend_tmootf_en : 1 ;
+ UINT32 m_neotf_en : 1 ;
+ UINT32 m_noetf_en : 1 ;
+ UINT32 : 24;
+
+
+ //REGISTER Post_proc_reg_1
+ UINT32 m_neotf_mode : 3 ;
+ UINT32 : 29;
+
+
+ //REGISTER Post_proc_reg_2
+ UINT32 m_noetf_mode : 3 ;
+ UINT32 : 5 ;
+ UINT32 m_noetf_max : 12;
+ UINT32 : 12;
+
+
+ //REGISTER Post_proc_reg_3
+ UINT32 m_pfront_tmootf_gain_table0 : 16;
+ UINT32 m_pfront_tmootf_gain_table1 : 16;
+
+
+ //REGISTER Post_proc_reg_4
+ UINT32 m_pfront_tmootf_gain_table2 : 16;
+ UINT32 m_pfront_tmootf_gain_table3 : 16;
+
+
+ //REGISTER Post_proc_reg_5
+ UINT32 m_pfront_tmootf_gain_table4 : 16;
+ UINT32 m_pfront_tmootf_gain_table5 : 16;
+
+
+ //REGISTER Post_proc_reg_6
+ UINT32 m_pfront_tmootf_gain_table6 : 16;
+ UINT32 m_pfront_tmootf_gain_table7 : 16;
+
+
+ //REGISTER Post_proc_reg_7
+ UINT32 m_pfront_tmootf_gain_table8 : 16;
+ UINT32 m_pfront_tmootf_gain_table9 : 16;
+
+
+ //REGISTER Post_proc_reg_8
+ UINT32 m_pfront_tmootf_gain_table10 : 16;
+ UINT32 m_pfront_tmootf_gain_table11 : 16;
+
+
+ //REGISTER Post_proc_reg_9
+ UINT32 m_pfront_tmootf_gain_table12 : 16;
+ UINT32 m_pfront_tmootf_gain_table13 : 16;
+
+
+ //REGISTER Post_proc_reg_10
+ UINT32 m_pfront_tmootf_gain_table14 : 16;
+ UINT32 m_pfront_tmootf_gain_table15 : 16;
+
+
+ //REGISTER Post_proc_reg_11
+ UINT32 m_pfront_tmootf_gain_table16 : 16;
+ UINT32 m_pfront_tmootf_gain_table17 : 16;
+
+
+ //REGISTER Post_proc_reg_12
+ UINT32 m_pfront_tmootf_gain_table18 : 16;
+ UINT32 m_pfront_tmootf_gain_table19 : 16;
+
+
+ //REGISTER Post_proc_reg_13
+ UINT32 m_pfront_tmootf_gain_table20 : 16;
+ UINT32 m_pfront_tmootf_gain_table21 : 16;
+
+
+ //REGISTER Post_proc_reg_14
+ UINT32 m_pfront_tmootf_gain_table22 : 16;
+ UINT32 m_pfront_tmootf_gain_table23 : 16;
+
+
+ //REGISTER Post_proc_reg_15
+ UINT32 m_pfront_tmootf_gain_table24 : 16;
+ UINT32 m_pfront_tmootf_gain_table25 : 16;
+
+
+ //REGISTER Post_proc_reg_16
+ UINT32 m_pfront_tmootf_gain_table26 : 16;
+ UINT32 m_pfront_tmootf_gain_table27 : 16;
+
+
+ //REGISTER Post_proc_reg_17
+ UINT32 m_pfront_tmootf_gain_table28 : 16;
+ UINT32 m_pfront_tmootf_gain_table29 : 16;
+
+
+ //REGISTER Post_proc_reg_18
+ UINT32 m_pfront_tmootf_gain_table30 : 16;
+ UINT32 m_pfront_tmootf_gain_table31 : 16;
+
+
+ //REGISTER Post_proc_reg_19
+ UINT32 m_pfront_tmootf_gain_table32 : 16;
+ UINT32 m_pfront_tmootf_gain_table33 : 16;
+
+
+ //REGISTER Post_proc_reg_20
+ UINT32 m_pfront_tmootf_gain_table34 : 16;
+ UINT32 m_pfront_tmootf_gain_table35 : 16;
+
+
+ //REGISTER Post_proc_reg_21
+ UINT32 m_pfront_tmootf_gain_table36 : 16;
+ UINT32 m_pfront_tmootf_gain_table37 : 16;
+
+
+ //REGISTER Post_proc_reg_22
+ UINT32 m_pfront_tmootf_gain_table38 : 16;
+ UINT32 m_pfront_tmootf_gain_table39 : 16;
+
+
+ //REGISTER Post_proc_reg_23
+ UINT32 m_pfront_tmootf_gain_table40 : 16;
+ UINT32 m_pfront_tmootf_gain_table41 : 16;
+
+
+ //REGISTER Post_proc_reg_24
+ UINT32 m_pfront_tmootf_gain_table42 : 16;
+ UINT32 m_pfront_tmootf_gain_table43 : 16;
+
+
+ //REGISTER Post_proc_reg_25
+ UINT32 m_pfront_tmootf_gain_table44 : 16;
+ UINT32 m_pfront_tmootf_gain_table45 : 16;
+
+
+ //REGISTER Post_proc_reg_26
+ UINT32 m_pfront_tmootf_gain_table46 : 16;
+ UINT32 m_pfront_tmootf_gain_table47 : 16;
+
+
+ //REGISTER Post_proc_reg_27
+ UINT32 m_pfront_tmootf_gain_table48 : 16;
+ UINT32 m_pfront_tmootf_gain_table49 : 16;
+
+
+ //REGISTER Post_proc_reg_28
+ UINT32 m_pfront_tmootf_gain_table50 : 16;
+ UINT32 m_pfront_tmootf_gain_table51 : 16;
+
+
+ //REGISTER Post_proc_reg_29
+ UINT32 m_pfront_tmootf_gain_table52 : 16;
+ UINT32 m_pfront_tmootf_gain_table53 : 16;
+
+
+ //REGISTER Post_proc_reg_30
+ UINT32 m_pfront_tmootf_gain_table54 : 16;
+ UINT32 m_pfront_tmootf_gain_table55 : 16;
+
+
+ //REGISTER Post_proc_reg_31
+ UINT32 m_pfront_tmootf_gain_table56 : 16;
+ UINT32 m_pfront_tmootf_gain_table57 : 16;
+
+
+ //REGISTER Post_proc_reg_32
+ UINT32 m_pfront_tmootf_gain_table58 : 16;
+ UINT32 m_pfront_tmootf_gain_table59 : 16;
+
+
+ //REGISTER Post_proc_reg_33
+ UINT32 m_pfront_tmootf_gain_table60 : 16;
+ UINT32 m_pfront_tmootf_gain_table61 : 16;
+
+
+ //REGISTER Post_proc_reg_34
+ UINT32 m_pfront_tmootf_gain_table62 : 16;
+ UINT32 m_pfront_tmootf_gain_table63 : 16;
+
+
+ //REGISTER Post_proc_reg_35
+ UINT32 m_pfront_tmootf_gain_table64 : 16;
+ UINT32 m_nfront_tmootf_shift_bits : 5 ;
+ UINT32 m_nfront_tmootf_rgb_mode : 2 ;
+ UINT32 : 9 ;
+
+
+ //REGISTER Post_proc_reg_36
+ UINT32 m_pend_tmootf_gain_table0 : 16;
+ UINT32 m_pend_tmootf_gain_table1 : 16;
+
+
+ //REGISTER Post_proc_reg_37
+ UINT32 m_pend_tmootf_gain_table2 : 16;
+ UINT32 m_pend_tmootf_gain_table3 : 16;
+
+
+ //REGISTER Post_proc_reg_38
+ UINT32 m_pend_tmootf_gain_table4 : 16;
+ UINT32 m_pend_tmootf_gain_table5 : 16;
+
+
+ //REGISTER Post_proc_reg_39
+ UINT32 m_pend_tmootf_gain_table6 : 16;
+ UINT32 m_pend_tmootf_gain_table7 : 16;
+
+
+ //REGISTER Post_proc_reg_40
+ UINT32 m_pend_tmootf_gain_table8 : 16;
+ UINT32 m_pend_tmootf_gain_table9 : 16;
+
+
+ //REGISTER Post_proc_reg_41
+ UINT32 m_pend_tmootf_gain_table10 : 16;
+ UINT32 m_pend_tmootf_gain_table11 : 16;
+
+
+ //REGISTER Post_proc_reg_42
+ UINT32 m_pend_tmootf_gain_table12 : 16;
+ UINT32 m_pend_tmootf_gain_table13 : 16;
+
+
+ //REGISTER Post_proc_reg_43
+ UINT32 m_pend_tmootf_gain_table14 : 16;
+ UINT32 m_pend_tmootf_gain_table15 : 16;
+
+
+ //REGISTER Post_proc_reg_44
+ UINT32 m_pend_tmootf_gain_table16 : 16;
+ UINT32 m_pend_tmootf_gain_table17 : 16;
+
+
+ //REGISTER Post_proc_reg_45
+ UINT32 m_pend_tmootf_gain_table18 : 16;
+ UINT32 m_pend_tmootf_gain_table19 : 16;
+
+
+ //REGISTER Post_proc_reg_46
+ UINT32 m_pend_tmootf_gain_table20 : 16;
+ UINT32 m_pend_tmootf_gain_table21 : 16;
+
+
+ //REGISTER Post_proc_reg_47
+ UINT32 m_pend_tmootf_gain_table22 : 16;
+ UINT32 m_pend_tmootf_gain_table23 : 16;
+
+
+ //REGISTER Post_proc_reg_48
+ UINT32 m_pend_tmootf_gain_table24 : 16;
+ UINT32 m_pend_tmootf_gain_table25 : 16;
+
+
+ //REGISTER Post_proc_reg_49
+ UINT32 m_pend_tmootf_gain_table26 : 16;
+ UINT32 m_pend_tmootf_gain_table27 : 16;
+
+
+ //REGISTER Post_proc_reg_50
+ UINT32 m_pend_tmootf_gain_table28 : 16;
+ UINT32 m_pend_tmootf_gain_table29 : 16;
+
+
+ //REGISTER Post_proc_reg_51
+ UINT32 m_pend_tmootf_gain_table30 : 16;
+ UINT32 m_pend_tmootf_gain_table31 : 16;
+
+
+ //REGISTER Post_proc_reg_52
+ UINT32 m_pend_tmootf_gain_table32 : 16;
+ UINT32 m_pend_tmootf_gain_table33 : 16;
+
+
+ //REGISTER Post_proc_reg_53
+ UINT32 m_pend_tmootf_gain_table34 : 16;
+ UINT32 m_pend_tmootf_gain_table35 : 16;
+
+
+ //REGISTER Post_proc_reg_54
+ UINT32 m_pend_tmootf_gain_table36 : 16;
+ UINT32 m_pend_tmootf_gain_table37 : 16;
+
+
+ //REGISTER Post_proc_reg_55
+ UINT32 m_pend_tmootf_gain_table38 : 16;
+ UINT32 m_pend_tmootf_gain_table39 : 16;
+
+
+ //REGISTER Post_proc_reg_56
+ UINT32 m_pend_tmootf_gain_table40 : 16;
+ UINT32 m_pend_tmootf_gain_table41 : 16;
+
+
+ //REGISTER Post_proc_reg_57
+ UINT32 m_pend_tmootf_gain_table42 : 16;
+ UINT32 m_pend_tmootf_gain_table43 : 16;
+
+
+ //REGISTER Post_proc_reg_58
+ UINT32 m_pend_tmootf_gain_table44 : 16;
+ UINT32 m_pend_tmootf_gain_table45 : 16;
+
+
+ //REGISTER Post_proc_reg_59
+ UINT32 m_pend_tmootf_gain_table46 : 16;
+ UINT32 m_pend_tmootf_gain_table47 : 16;
+
+
+ //REGISTER Post_proc_reg_60
+ UINT32 m_pend_tmootf_gain_table48 : 16;
+ UINT32 m_pend_tmootf_gain_table49 : 16;
+
+
+ //REGISTER Post_proc_reg_61
+ UINT32 m_pend_tmootf_gain_table50 : 16;
+ UINT32 m_pend_tmootf_gain_table51 : 16;
+
+
+ //REGISTER Post_proc_reg_62
+ UINT32 m_pend_tmootf_gain_table52 : 16;
+ UINT32 m_pend_tmootf_gain_table53 : 16;
+
+
+ //REGISTER Post_proc_reg_63
+ UINT32 m_pend_tmootf_gain_table54 : 16;
+ UINT32 m_pend_tmootf_gain_table55 : 16;
+
+
+ //REGISTER post_proc_reg_64
+ UINT32 m_pend_tmootf_gain_table56 : 16;
+ UINT32 m_pend_tmootf_gain_table57 : 16;
+
+
+ //REGISTER Post_proc_reg_65
+ UINT32 m_pend_tmootf_gain_table58 : 16;
+ UINT32 m_pend_tmootf_gain_table59 : 16;
+
+
+ //REGISTER Post_proc_reg_66
+ UINT32 m_pend_tmootf_gain_table60 : 16;
+ UINT32 m_pend_tmootf_gain_table61 : 16;
+
+
+ //REGISTER Post_proc_reg_67
+ UINT32 m_pend_tmootf_gain_table62 : 16;
+ UINT32 m_pend_tmootf_gain_table63 : 16;
+
+
+ //REGISTER Post_proc_reg_68
+ UINT32 m_pend_tmootf_gain_table64 : 16;
+ UINT32 m_nend_tmootf_shift_bits : 5 ;
+ UINT32 m_nend_tmootf_rgb_mode : 2 ;
+ UINT32 : 9 ;
+
+
+ //REGISTER Post_proc_reg_69
+ UINT32 m_pmatrix_table0 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table1 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_70
+ UINT32 m_pmatrix_table2 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table3 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_71
+ UINT32 m_pmatrix_table4 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table5 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_72
+ UINT32 m_pmatrix_table6 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table7 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_73
+ UINT32 m_pmatrix_table8 : 14;
+ UINT32 : 18;
+
+
+ //REGISTER Post_proc_reg_74
+ UINT32 m_pmatrix_offset0 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER Post_proc_reg_75
+ UINT32 m_pmatrix_offset1 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER Post_proc_reg_76
+ UINT32 m_pmatrix_offset2 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER Post_proc_reg_77
+ UINT32 m_ngain_to_full : 16;
+ UINT32 : 16;
+
+
+ //REGISTER Post_proc_reg_78
+ UINT32 m_pendmatrix_table0 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pendmatrix_table1 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_79
+ UINT32 m_pendmatrix_table2 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pendmatrix_table3 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_80
+ UINT32 m_pendmatrix_table4 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pendmatrix_table5 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_81
+ UINT32 m_pendmatrix_table6 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pendmatrix_table7 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Post_proc_reg_82
+ UINT32 m_pendmatrix_table8 : 14;
+ UINT32 : 18;
+
+
+ //REGISTER Post_proc_reg_83
+ UINT32 m_pendmatrix_offset0 : 13;
+ UINT32 : 19;
+
+
+ //REGISTER Post_proc_reg_84
+ UINT32 m_pendmatrix_offset1 : 13;
+ UINT32 : 19;
+
+
+ //REGISTER Post_proc_reg_85
+ UINT32 m_pendmatrix_offset2 : 13;
+ UINT32 : 19;
+
+
+ };
+
+ INT32 value32[86];
+
+}OUTCTRL_PROC_X_REG;
+
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef OUTCTRL_TOP_X_REG_H
+#define OUTCTRL_TOP_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER Out_ctrl_reg_0
+ UINT32 m_n_inwdith : 13;
+ UINT32 : 3 ;
+ UINT32 m_n_inheight : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_1
+ UINT32 scale_wdith : 13;
+ UINT32 : 3 ;
+ UINT32 scale_height : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_2
+ UINT32 : 32;
+
+
+ //REGISTER Out_ctrl_reg_3
+ UINT32 : 32;
+
+
+ //REGISTER Out_ctrl_reg_4
+ UINT32 acad_en : 1 ;
+ UINT32 dsc_dfc_switch_en : 1 ;
+ UINT32 : 30;
+
+
+ //REGISTER Out_ctrl_reg_5
+ UINT32 scale_en : 1 ;
+ UINT32 dither_en : 1 ;
+ UINT32 dither_mode : 1 ;
+ UINT32 dither_auto_temp : 1 ;
+ UINT32 dither_out_dpth0 : 4 ;
+ UINT32 dither_out_dpth1 : 4 ;
+ UINT32 dither_out_dpth2 : 4 ;
+ UINT32 dither_temp_value : 8 ;
+ UINT32 dither_rotate_mode : 2 ;
+ UINT32 dither_pattern_bit : 3 ;
+ UINT32 : 3 ;
+
+
+ //REGISTER Out_ctrl_reg_6
+ UINT32 sbs_en : 1 ;
+ UINT32 split_en : 1 ;
+ UINT32 rgb2yuv_en : 1 ;
+ UINT32 narrow_yuv_en : 1 ;
+ UINT32 cmd_screen : 1 ;
+ UINT32 frame_timing_en : 1 ;
+ UINT32 cmd_wait_en : 1 ;
+ UINT32 cmd_wait_te : 1 ;
+ UINT32 reg06_bit8_dmy : 1 ;
+ UINT32 tm_ctrl_reload_option : 1 ;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_7
+ UINT32 hblank : 12;
+ UINT32 : 4 ;
+ UINT32 split_overlap : 10;
+ UINT32 : 6 ;
+
+
+ //REGISTER Out_ctrl_reg_8
+ UINT32 rgb2yuv_matrix00 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix01 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_9
+ UINT32 rgb2yuv_matrix02 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix03 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_10
+ UINT32 rgb2yuv_matrix10 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix11 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_11
+ UINT32 rgb2yuv_matrix12 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix13 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_12
+ UINT32 rgb2yuv_matrix20 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix21 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_13
+ UINT32 rgb2yuv_matrix22 : 14;
+ UINT32 : 2 ;
+ UINT32 rgb2yuv_matrix23 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_14
+ UINT32 dither_bayer_map00 : 8 ;
+ UINT32 dither_bayer_map01 : 8 ;
+ UINT32 dither_bayer_map02 : 8 ;
+ UINT32 dither_bayer_map03 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_15
+ UINT32 dither_bayer_map04 : 8 ;
+ UINT32 dither_bayer_map05 : 8 ;
+ UINT32 dither_bayer_map06 : 8 ;
+ UINT32 dither_bayer_map07 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_16
+ UINT32 dither_bayer_map10 : 8 ;
+ UINT32 dither_bayer_map11 : 8 ;
+ UINT32 dither_bayer_map12 : 8 ;
+ UINT32 dither_bayer_map13 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_17
+ UINT32 dither_bayer_map14 : 8 ;
+ UINT32 dither_bayer_map15 : 8 ;
+ UINT32 dither_bayer_map16 : 8 ;
+ UINT32 dither_bayer_map17 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_18
+ UINT32 dither_bayer_map20 : 8 ;
+ UINT32 dither_bayer_map21 : 8 ;
+ UINT32 dither_bayer_map22 : 8 ;
+ UINT32 dither_bayer_map23 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_19
+ UINT32 dither_bayer_map24 : 8 ;
+ UINT32 dither_bayer_map25 : 8 ;
+ UINT32 dither_bayer_map26 : 8 ;
+ UINT32 dither_bayer_map27 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_20
+ UINT32 dither_bayer_map30 : 8 ;
+ UINT32 dither_bayer_map31 : 8 ;
+ UINT32 dither_bayer_map32 : 8 ;
+ UINT32 dither_bayer_map33 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_21
+ UINT32 dither_bayer_map34 : 8 ;
+ UINT32 dither_bayer_map35 : 8 ;
+ UINT32 dither_bayer_map36 : 8 ;
+ UINT32 dither_bayer_map37 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_22
+ UINT32 dither_bayer_map40 : 8 ;
+ UINT32 dither_bayer_map41 : 8 ;
+ UINT32 dither_bayer_map42 : 8 ;
+ UINT32 dither_bayer_map43 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_23
+ UINT32 dither_bayer_map44 : 8 ;
+ UINT32 dither_bayer_map45 : 8 ;
+ UINT32 dither_bayer_map46 : 8 ;
+ UINT32 dither_bayer_map47 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_24
+ UINT32 dither_bayer_map50 : 8 ;
+ UINT32 dither_bayer_map51 : 8 ;
+ UINT32 dither_bayer_map52 : 8 ;
+ UINT32 dither_bayer_map53 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_25
+ UINT32 dither_bayer_map54 : 8 ;
+ UINT32 dither_bayer_map55 : 8 ;
+ UINT32 dither_bayer_map56 : 8 ;
+ UINT32 dither_bayer_map57 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_26
+ UINT32 dither_bayer_map60 : 8 ;
+ UINT32 dither_bayer_map61 : 8 ;
+ UINT32 dither_bayer_map62 : 8 ;
+ UINT32 dither_bayer_map63 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_27
+ UINT32 dither_bayer_map64 : 8 ;
+ UINT32 dither_bayer_map65 : 8 ;
+ UINT32 dither_bayer_map66 : 8 ;
+ UINT32 dither_bayer_map67 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_28
+ UINT32 dither_bayer_map70 : 8 ;
+ UINT32 dither_bayer_map71 : 8 ;
+ UINT32 dither_bayer_map72 : 8 ;
+ UINT32 dither_bayer_map73 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_29
+ UINT32 dither_bayer_map74 : 8 ;
+ UINT32 dither_bayer_map75 : 8 ;
+ UINT32 dither_bayer_map76 : 8 ;
+ UINT32 dither_bayer_map77 : 8 ;
+
+
+ //REGISTER Out_ctrl_reg_30
+ UINT32 dfc_low_thre : 12;
+ UINT32 : 4 ;
+ UINT32 dfc_high_thre : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER Out_ctrl_reg_31
+ UINT32 split_cfg_manual_en : 1 ;
+ UINT32 : 7 ;
+ UINT32 disp_ready_man_en : 1 ;
+ UINT32 disp_ready_1_non_active : 1 ;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_32
+ UINT32 hfp : 12;
+ UINT32 : 4 ;
+ UINT32 hbp : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER Out_ctrl_reg_33
+ UINT32 vfp : 12;
+ UINT32 : 4 ;
+ UINT32 vbp : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER Out_ctrl_reg_34
+ UINT32 hsync_width : 10;
+ UINT32 : 2 ;
+ UINT32 hsp : 1 ;
+ UINT32 : 3 ;
+ UINT32 vsync_width : 10;
+ UINT32 : 2 ;
+ UINT32 vsp : 1 ;
+ UINT32 : 3 ;
+
+
+ //REGISTER Out_ctrl_reg_35
+ UINT32 h_active : 14;
+ UINT32 : 2 ;
+ UINT32 v_active : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_36
+ UINT32 user : 4 ;
+ UINT32 : 28;
+
+
+ //REGISTER Out_ctrl_reg_37
+ UINT32 fm_cmd_timeout_num : 24;
+ UINT32 fm_cmd_timeout_eq_eof : 1 ;
+ UINT32 : 7 ;
+
+
+ //REGISTER Out_ctrl_reg_38
+ UINT32 back_ground_r : 12;
+ UINT32 : 4 ;
+ UINT32 back_ground_g : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER Out_ctrl_reg_39
+ UINT32 back_ground_b : 12;
+ UINT32 : 20;
+
+
+ //REGISTER Out_ctrl_reg_40
+ UINT32 drift_timeout : 12;
+ UINT32 : 20;
+
+
+ //REGISTER Out_ctrl_reg_41
+ UINT32 eof_ln_dly : 10;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_42
+ UINT32 sof_pre_ln_num : 10;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_43
+ UINT32 cfg_ln_num_intp : 14;
+ UINT32 : 18;
+
+
+ //REGISTER Out_ctrl_reg_44
+ UINT32 sof0_irq_raw : 1 ;
+ UINT32 eof0_irq_raw : 1 ;
+ UINT32 cfg_eof0_irq_raw : 1 ;
+ UINT32 cfg_eol0_irq_raw : 1 ;
+ UINT32 underflow0_irq_raw : 1 ;
+ UINT32 sof1_irq_raw : 1 ;
+ UINT32 eof1_irq_raw : 1 ;
+ UINT32 cfg_eof1_irq_raw : 1 ;
+ UINT32 cfg_eol1_irq_raw : 1 ;
+ UINT32 underflow1_irq_raw : 1 ;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_45
+ UINT32 line_irq_raw : 1 ;
+ UINT32 drift_timeout_irq_raw : 1 ;
+ UINT32 acad_irq_raw : 1 ;
+ UINT32 dsc0_overflow_irq_raw : 1 ;
+ UINT32 dsc1_overflow_irq_raw : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER Out_ctrl_reg_46
+ UINT32 sof0_irq_mask : 1 ;
+ UINT32 eof0_irq_mask : 1 ;
+ UINT32 cfg_eof0_irq_mask : 1 ;
+ UINT32 cfg_eol0_irq_mask : 1 ;
+ UINT32 underflow0_irq_mask : 1 ;
+ UINT32 sof1_irq_mask : 1 ;
+ UINT32 eof1_irq_mask : 1 ;
+ UINT32 cfg_eof1_irq_mask : 1 ;
+ UINT32 cfg_eol1_irq_mask : 1 ;
+ UINT32 underflow1_irq_mask : 1 ;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_47
+ UINT32 line_irq_mask : 1 ;
+ UINT32 drift_timeout_irq_mask : 1 ;
+ UINT32 acad_irq_mask : 1 ;
+ UINT32 dsc0_overflow_mask : 1 ;
+ UINT32 dsc1_overflow_mask : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER Out_ctrl_reg_48
+ UINT32 sof0_irq_status : 1 ;
+ UINT32 eof0_irq_status : 1 ;
+ UINT32 cfg_eof0_irq_status : 1 ;
+ UINT32 cfg_eol0_irq_status : 1 ;
+ UINT32 underflow0_irq_status : 1 ;
+ UINT32 sof1_irq_status : 1 ;
+ UINT32 eof1_irq_status : 1 ;
+ UINT32 cfg_eof1_irq_status : 1 ;
+ UINT32 cfg_eol1_irq_status : 1 ;
+ UINT32 underflow1_irq_status : 1 ;
+ UINT32 : 22;
+
+
+ //REGISTER Out_ctrl_reg_49
+ UINT32 line0_irq_status : 1 ;
+ UINT32 drift_timeout_irq_status : 1 ;
+ UINT32 acad_irq_status : 1 ;
+ UINT32 dsc0_overflow_irq_sta : 1 ;
+ UINT32 dsc1_overflow_irq_sta : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER Out_ctrl_reg_50
+ UINT32 postproc_ln_cnt : 14;
+ UINT32 : 2 ;
+ UINT32 postproc_pix_cnt : 13;
+ UINT32 : 3 ;
+
+
+ //REGISTER Out_ctrl_reg_51
+ UINT32 dither_ln_cnt : 14;
+ UINT32 : 2 ;
+ UINT32 dither_pix_cnt : 13;
+ UINT32 : 3 ;
+
+
+ //REGISTER Out_ctrl_reg_52
+ UINT32 dat_convert_ln_cnt : 14;
+ UINT32 : 2 ;
+ UINT32 dat_convert_pix_cnt : 13;
+ UINT32 : 3 ;
+
+
+ //REGISTER Out_ctrl_reg_53
+ UINT32 merge_ln_cnt : 14;
+ UINT32 : 2 ;
+ UINT32 merge_pix_cnt : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER Out_ctrl_reg_54
+ UINT32 split_ln_cnt : 14;
+ UINT32 : 2 ;
+ UINT32 split_pix_cnt : 14;
+ UINT32 : 2 ;
+
+
+ };
+
+ INT32 value32[55];
+
+}OUTCTRL_TOP_X_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef PREPIPE_LAYER_PROC_X_REG_H
+#define PREPIPE_LAYER_PROC_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER layer_proc_reg_0
+ UINT32 m_nlayer_pro_en : 1 ;
+ UINT32 m_ngain_to_full_en : 1 ;
+ UINT32 m_nmatrix_en : 1 ;
+ UINT32 m_nfront_tmootf_en : 1 ;
+ UINT32 m_nend_tmootf_en : 1 ;
+ UINT32 m_ncolor_key_en : 1 ;
+ UINT32 m_neotf_en : 1 ;
+ UINT32 m_noetf_en : 1 ;
+ UINT32 : 24;
+
+
+ //REGISTER layer_proc_reg_1
+ UINT32 rsvt : 32;
+
+
+ //REGISTER layer_proc_reg_2
+ UINT32 m_neotf_mode : 3 ;
+ UINT32 m_noetf_mode : 3 ;
+ UINT32 : 2 ;
+ UINT32 m_noetf_max : 12;
+ UINT32 : 12;
+
+
+ //REGISTER layer_proc_reg_3
+ UINT32 m_pfront_tmootf_gain_table0 : 16;
+ UINT32 m_pfront_tmootf_gain_table1 : 16;
+
+
+ //REGISTER layer_proc_reg_4
+ UINT32 m_pfront_tmootf_gain_table2 : 16;
+ UINT32 m_pfront_tmootf_gain_table3 : 16;
+
+
+ //REGISTER layer_proc_reg_5
+ UINT32 m_pfront_tmootf_gain_table4 : 16;
+ UINT32 m_pfront_tmootf_gain_table5 : 16;
+
+
+ //REGISTER layer_proc_reg_6
+ UINT32 m_pfront_tmootf_gain_table6 : 16;
+ UINT32 m_pfront_tmootf_gain_table7 : 16;
+
+
+ //REGISTER layer_proc_reg_7
+ UINT32 m_pfront_tmootf_gain_table8 : 16;
+ UINT32 m_pfront_tmootf_gain_table9 : 16;
+
+
+ //REGISTER layer_proc_reg_8
+ UINT32 m_pfront_tmootf_gain_table10 : 16;
+ UINT32 m_pfront_tmootf_gain_table11 : 16;
+
+
+ //REGISTER layer_proc_reg_9
+ UINT32 m_pfront_tmootf_gain_table12 : 16;
+ UINT32 m_pfront_tmootf_gain_table13 : 16;
+
+
+ //REGISTER layer_proc_reg_10
+ UINT32 m_pfront_tmootf_gain_table14 : 16;
+ UINT32 m_pfront_tmootf_gain_table15 : 16;
+
+
+ //REGISTER layer_proc_reg_11
+ UINT32 m_pfront_tmootf_gain_table16 : 16;
+ UINT32 m_pfront_tmootf_gain_table17 : 16;
+
+
+ //REGISTER layer_proc_reg_12
+ UINT32 m_pfront_tmootf_gain_table18 : 16;
+ UINT32 m_pfront_tmootf_gain_table19 : 16;
+
+
+ //REGISTER layer_proc_reg_13
+ UINT32 m_pfront_tmootf_gain_table20 : 16;
+ UINT32 m_pfront_tmootf_gain_table21 : 16;
+
+
+ //REGISTER layer_proc_reg_14
+ UINT32 m_pfront_tmootf_gain_table22 : 16;
+ UINT32 m_pfront_tmootf_gain_table23 : 16;
+
+
+ //REGISTER layer_proc_reg_15
+ UINT32 m_pfront_tmootf_gain_table24 : 16;
+ UINT32 m_pfront_tmootf_gain_table25 : 16;
+
+
+ //REGISTER layer_proc_reg_16
+ UINT32 m_pfront_tmootf_gain_table26 : 16;
+ UINT32 m_pfront_tmootf_gain_table27 : 16;
+
+
+ //REGISTER layer_proc_reg_17
+ UINT32 m_pfront_tmootf_gain_table28 : 16;
+ UINT32 m_pfront_tmootf_gain_table29 : 16;
+
+
+ //REGISTER layer_proc_reg_18
+ UINT32 m_pfront_tmootf_gain_table30 : 16;
+ UINT32 m_pfront_tmootf_gain_table31 : 16;
+
+
+ //REGISTER layer_proc_reg_19
+ UINT32 m_pfront_tmootf_gain_table32 : 16;
+ UINT32 m_pfront_tmootf_gain_table33 : 16;
+
+
+ //REGISTER layer_proc_reg_20
+ UINT32 m_pfront_tmootf_gain_table34 : 16;
+ UINT32 m_pfront_tmootf_gain_table35 : 16;
+
+
+ //REGISTER layer_proc_reg_21
+ UINT32 m_pfront_tmootf_gain_table36 : 16;
+ UINT32 m_pfront_tmootf_gain_table37 : 16;
+
+
+ //REGISTER layer_proc_reg_22
+ UINT32 m_pfront_tmootf_gain_table38 : 16;
+ UINT32 m_pfront_tmootf_gain_table39 : 16;
+
+
+ //REGISTER layer_proc_reg_23
+ UINT32 m_pfront_tmootf_gain_table40 : 16;
+ UINT32 m_pfront_tmootf_gain_table41 : 16;
+
+
+ //REGISTER layer_proc_reg_24
+ UINT32 m_pfront_tmootf_gain_table42 : 16;
+ UINT32 m_pfront_tmootf_gain_table43 : 16;
+
+
+ //REGISTER layer_proc_reg_25
+ UINT32 m_pfront_tmootf_gain_table44 : 16;
+ UINT32 m_pfront_tmootf_gain_table45 : 16;
+
+
+ //REGISTER layer_proc_reg_26
+ UINT32 m_pfront_tmootf_gain_table46 : 16;
+ UINT32 m_pfront_tmootf_gain_table47 : 16;
+
+
+ //REGISTER layer_proc_reg_27
+ UINT32 m_pfront_tmootf_gain_table48 : 16;
+ UINT32 m_pfront_tmootf_gain_table49 : 16;
+
+
+ //REGISTER layer_proc_reg_28
+ UINT32 m_pfront_tmootf_gain_table50 : 16;
+ UINT32 m_pfront_tmootf_gain_table51 : 16;
+
+
+ //REGISTER layer_proc_reg_29
+ UINT32 m_pfront_tmootf_gain_table52 : 16;
+ UINT32 m_pfront_tmootf_gain_table53 : 16;
+
+
+ //REGISTER layer_proc_reg_30
+ UINT32 m_pfront_tmootf_gain_table54 : 16;
+ UINT32 m_pfront_tmootf_gain_table55 : 16;
+
+
+ //REGISTER layer_proc_reg_31
+ UINT32 m_pfront_tmootf_gain_table56 : 16;
+ UINT32 m_pfront_tmootf_gain_table57 : 16;
+
+
+ //REGISTER layer_proc_reg_32
+ UINT32 m_pfront_tmootf_gain_table58 : 16;
+ UINT32 m_pfront_tmootf_gain_table59 : 16;
+
+
+ //REGISTER layer_proc_reg_33
+ UINT32 m_pfront_tmootf_gain_table60 : 16;
+ UINT32 m_pfront_tmootf_gain_table61 : 16;
+
+
+ //REGISTER layer_proc_reg_34
+ UINT32 m_pfront_tmootf_gain_table62 : 16;
+ UINT32 m_pfront_tmootf_gain_table63 : 16;
+
+
+ //REGISTER layer_proc_reg_35
+ UINT32 m_pfront_tmootf_gain_table64 : 16;
+ UINT32 m_nfront_tmootf_shift_bits : 5 ;
+ UINT32 m_nfront_tmootf_rgb_mode : 2 ;
+ UINT32 : 9 ;
+
+
+ //REGISTER layer_proc_reg_36
+ UINT32 m_pend_tmootf_gain_table0 : 16;
+ UINT32 m_pend_tmootf_gain_table1 : 16;
+
+
+ //REGISTER layer_proc_reg_37
+ UINT32 m_pend_tmootf_gain_table2 : 16;
+ UINT32 m_pend_tmootf_gain_table3 : 16;
+
+
+ //REGISTER layer_proc_reg_38
+ UINT32 m_pend_tmootf_gain_table4 : 16;
+ UINT32 m_pend_tmootf_gain_table5 : 16;
+
+
+ //REGISTER layer_proc_reg_39
+ UINT32 m_pend_tmootf_gain_table6 : 16;
+ UINT32 m_pend_tmootf_gain_table7 : 16;
+
+
+ //REGISTER layer_proc_reg_40
+ UINT32 m_pend_tmootf_gain_table8 : 16;
+ UINT32 m_pend_tmootf_gain_table9 : 16;
+
+
+ //REGISTER layer_proc_reg_41
+ UINT32 m_pend_tmootf_gain_table10 : 16;
+ UINT32 m_pend_tmootf_gain_table11 : 16;
+
+
+ //REGISTER layer_proc_reg_42
+ UINT32 m_pend_tmootf_gain_table12 : 16;
+ UINT32 m_pend_tmootf_gain_table13 : 16;
+
+
+ //REGISTER layer_proc_reg_43
+ UINT32 m_pend_tmootf_gain_table14 : 16;
+ UINT32 m_pend_tmootf_gain_table15 : 16;
+
+
+ //REGISTER layer_proc_reg_44
+ UINT32 m_pend_tmootf_gain_table16 : 16;
+ UINT32 m_pend_tmootf_gain_table17 : 16;
+
+
+ //REGISTER layer_proc_reg_45
+ UINT32 m_pend_tmootf_gain_table18 : 16;
+ UINT32 m_pend_tmootf_gain_table19 : 16;
+
+
+ //REGISTER layer_proc_reg_46
+ UINT32 m_pend_tmootf_gain_table20 : 16;
+ UINT32 m_pend_tmootf_gain_table21 : 16;
+
+
+ //REGISTER layer_proc_reg_47
+ UINT32 m_pend_tmootf_gain_table22 : 16;
+ UINT32 m_pend_tmootf_gain_table23 : 16;
+
+
+ //REGISTER layer_proc_reg_48
+ UINT32 m_pend_tmootf_gain_table24 : 16;
+ UINT32 m_pend_tmootf_gain_table25 : 16;
+
+
+ //REGISTER layer_proc_reg_49
+ UINT32 m_pend_tmootf_gain_table26 : 16;
+ UINT32 m_pend_tmootf_gain_table27 : 16;
+
+
+ //REGISTER layer_proc_reg_50
+ UINT32 m_pend_tmootf_gain_table28 : 16;
+ UINT32 m_pend_tmootf_gain_table29 : 16;
+
+
+ //REGISTER layer_proc_reg_51
+ UINT32 m_pend_tmootf_gain_table30 : 16;
+ UINT32 m_pend_tmootf_gain_table31 : 16;
+
+
+ //REGISTER layer_proc_reg_52
+ UINT32 m_pend_tmootf_gain_table32 : 16;
+ UINT32 m_pend_tmootf_gain_table33 : 16;
+
+
+ //REGISTER layer_proc_reg_53
+ UINT32 m_pend_tmootf_gain_table34 : 16;
+ UINT32 m_pend_tmootf_gain_table35 : 16;
+
+
+ //REGISTER layer_proc_reg_54
+ UINT32 m_pend_tmootf_gain_table36 : 16;
+ UINT32 m_pend_tmootf_gain_table37 : 16;
+
+
+ //REGISTER layer_proc_reg_55
+ UINT32 m_pend_tmootf_gain_table38 : 16;
+ UINT32 m_pend_tmootf_gain_table39 : 16;
+
+
+ //REGISTER layer_proc_reg_56
+ UINT32 m_pend_tmootf_gain_table40 : 16;
+ UINT32 m_pend_tmootf_gain_table41 : 16;
+
+
+ //REGISTER layer_proc_reg_57
+ UINT32 m_pend_tmootf_gain_table42 : 16;
+ UINT32 m_pend_tmootf_gain_table43 : 16;
+
+
+ //REGISTER layer_proc_reg_58
+ UINT32 m_pend_tmootf_gain_table44 : 16;
+ UINT32 m_pend_tmootf_gain_table45 : 16;
+
+
+ //REGISTER layer_proc_reg_59
+ UINT32 m_pend_tmootf_gain_table46 : 16;
+ UINT32 m_pend_tmootf_gain_table47 : 16;
+
+
+ //REGISTER layer_proc_reg_60
+ UINT32 m_pend_tmootf_gain_table48 : 16;
+ UINT32 m_pend_tmootf_gain_table49 : 16;
+
+
+ //REGISTER layer_proc_reg_61
+ UINT32 m_pend_tmootf_gain_table50 : 16;
+ UINT32 m_pend_tmootf_gain_table51 : 16;
+
+
+ //REGISTER layer_proc_reg_62
+ UINT32 m_pend_tmootf_gain_table52 : 16;
+ UINT32 m_pend_tmootf_gain_table53 : 16;
+
+
+ //REGISTER layer_proc_reg_63
+ UINT32 m_pend_tmootf_gain_table54 : 16;
+ UINT32 m_pend_tmootf_gain_table55 : 16;
+
+
+ //REGISTER layer_proc_reg_64
+ UINT32 m_pend_tmootf_gain_table56 : 16;
+ UINT32 m_pend_tmootf_gain_table57 : 16;
+
+
+ //REGISTER layer_proc_reg_65
+ UINT32 m_pend_tmootf_gain_table58 : 16;
+ UINT32 m_pend_tmootf_gain_table59 : 16;
+
+
+ //REGISTER layer_proc_reg_66
+ UINT32 m_pend_tmootf_gain_table60 : 16;
+ UINT32 m_pend_tmootf_gain_table61 : 16;
+
+
+ //REGISTER layer_proc_reg_67
+ UINT32 m_pend_tmootf_gain_table62 : 16;
+ UINT32 m_pend_tmootf_gain_table63 : 16;
+
+
+ //REGISTER layer_proc_reg_68
+ UINT32 m_pend_tmootf_gain_table64 : 16;
+ UINT32 m_nend_tmootf_shift_bits : 5 ;
+ UINT32 m_nend_tmootf_rgb_mode : 2 ;
+ UINT32 : 9 ;
+
+
+ //REGISTER layer_proc_reg_69
+ UINT32 m_pmatrix_table0 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table1 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER layer_proc_reg_70
+ UINT32 m_pmatrix_table2 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table3 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER layer_proc_reg_71
+ UINT32 m_pmatrix_table4 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table5 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER layer_proc_reg_72
+ UINT32 m_pmatrix_table6 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table7 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER layer_proc_reg_73
+ UINT32 m_pmatrix_table8 : 14;
+ UINT32 : 18;
+
+
+ //REGISTER layer_proc_reg_74
+ UINT32 m_pmatrix_offset0 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER layer_proc_reg_75
+ UINT32 m_pmatrix_offset1 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER layer_proc_reg_76
+ UINT32 m_pmatrix_offset2 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER layer_proc_reg_77
+ UINT32 m_ngain_to_full : 16;
+ UINT32 m_pcolor_key_R_thr0 : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER layer_proc_reg_78
+ UINT32 m_pcolor_key_R_thr1 : 12;
+ UINT32 : 4 ;
+ UINT32 m_pcolor_key_G_thr0 : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER layer_proc_reg_79
+ UINT32 m_pcolor_key_G_thr1 : 12;
+ UINT32 : 4 ;
+ UINT32 m_pcolor_key_B_thr0 : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER layer_proc_reg_80
+ UINT32 m_pcolor_key_B_thr1 : 12;
+ UINT32 : 20;
+
+
+ } b;
+
+ struct
+ {
+ //REGISTER layer_proc_reg_0
+ UINT32 layer_proc_reg_0;
+
+
+ //REGISTER layer_proc_reg_1
+ UINT32 layer_proc_reg_1;
+
+
+ //REGISTER layer_proc_reg_2
+ UINT32 layer_proc_reg_2;
+
+
+ //REGISTER layer_proc_reg_3
+ UINT32 layer_proc_reg_3;
+
+
+ //REGISTER layer_proc_reg_4
+ UINT32 layer_proc_reg_4;
+
+
+ //REGISTER layer_proc_reg_5
+ UINT32 layer_proc_reg_5;
+
+
+ //REGISTER layer_proc_reg_6
+ UINT32 layer_proc_reg_6;
+
+
+ //REGISTER layer_proc_reg_7
+ UINT32 layer_proc_reg_7;
+
+
+ //REGISTER layer_proc_reg_8
+ UINT32 layer_proc_reg_8;
+
+
+ //REGISTER layer_proc_reg_9
+ UINT32 layer_proc_reg_9;
+
+
+ //REGISTER layer_proc_reg_10
+ UINT32 layer_proc_reg_10;
+
+
+ //REGISTER layer_proc_reg_11
+ UINT32 layer_proc_reg_11;
+
+
+ //REGISTER layer_proc_reg_12
+ UINT32 layer_proc_reg_12;
+
+
+ //REGISTER layer_proc_reg_13
+ UINT32 layer_proc_reg_13;
+
+
+ //REGISTER layer_proc_reg_14
+ UINT32 layer_proc_reg_14;
+
+
+ //REGISTER layer_proc_reg_15
+ UINT32 layer_proc_reg_15;
+
+
+ //REGISTER layer_proc_reg_16
+ UINT32 layer_proc_reg_16;
+
+
+ //REGISTER layer_proc_reg_17
+ UINT32 layer_proc_reg_17;
+
+
+ //REGISTER layer_proc_reg_18
+ UINT32 layer_proc_reg_18;
+
+
+ //REGISTER layer_proc_reg_19
+ UINT32 layer_proc_reg_19;
+
+
+ //REGISTER layer_proc_reg_20
+ UINT32 layer_proc_reg_20;
+
+
+ //REGISTER layer_proc_reg_21
+ UINT32 layer_proc_reg_21;
+
+
+ //REGISTER layer_proc_reg_22
+ UINT32 layer_proc_reg_22;
+
+
+ //REGISTER layer_proc_reg_23
+ UINT32 layer_proc_reg_23;
+
+
+ //REGISTER layer_proc_reg_24
+ UINT32 layer_proc_reg_24;
+
+
+ //REGISTER layer_proc_reg_25
+ UINT32 layer_proc_reg_25;
+
+
+ //REGISTER layer_proc_reg_26
+ UINT32 layer_proc_reg_26;
+
+
+ //REGISTER layer_proc_reg_27
+ UINT32 layer_proc_reg_27;
+
+
+ //REGISTER layer_proc_reg_28
+ UINT32 layer_proc_reg_28;
+
+
+ //REGISTER layer_proc_reg_29
+ UINT32 layer_proc_reg_29;
+
+
+ //REGISTER layer_proc_reg_30
+ UINT32 layer_proc_reg_30;
+
+
+ //REGISTER layer_proc_reg_31
+ UINT32 layer_proc_reg_31;
+
+
+ //REGISTER layer_proc_reg_32
+ UINT32 layer_proc_reg_32;
+
+
+ //REGISTER layer_proc_reg_33
+ UINT32 layer_proc_reg_33;
+
+
+ //REGISTER layer_proc_reg_34
+ UINT32 layer_proc_reg_34;
+
+
+ //REGISTER layer_proc_reg_35
+ UINT32 layer_proc_reg_35;
+
+
+ //REGISTER layer_proc_reg_36
+ UINT32 layer_proc_reg_36;
+
+
+ //REGISTER layer_proc_reg_37
+ UINT32 layer_proc_reg_37;
+
+
+ //REGISTER layer_proc_reg_38
+ UINT32 layer_proc_reg_38;
+
+
+ //REGISTER layer_proc_reg_39
+ UINT32 layer_proc_reg_39;
+
+
+ //REGISTER layer_proc_reg_40
+ UINT32 layer_proc_reg_40;
+
+
+ //REGISTER layer_proc_reg_41
+ UINT32 layer_proc_reg_41;
+
+
+ //REGISTER layer_proc_reg_42
+ UINT32 layer_proc_reg_42;
+
+
+ //REGISTER layer_proc_reg_43
+ UINT32 layer_proc_reg_43;
+
+
+ //REGISTER layer_proc_reg_44
+ UINT32 layer_proc_reg_44;
+
+
+ //REGISTER layer_proc_reg_45
+ UINT32 layer_proc_reg_45;
+
+
+ //REGISTER layer_proc_reg_46
+ UINT32 layer_proc_reg_46;
+
+
+ //REGISTER layer_proc_reg_47
+ UINT32 layer_proc_reg_47;
+
+
+ //REGISTER layer_proc_reg_48
+ UINT32 layer_proc_reg_48;
+
+
+ //REGISTER layer_proc_reg_49
+ UINT32 layer_proc_reg_49;
+
+
+ //REGISTER layer_proc_reg_50
+ UINT32 layer_proc_reg_50;
+
+
+ //REGISTER layer_proc_reg_51
+ UINT32 layer_proc_reg_51;
+
+
+ //REGISTER layer_proc_reg_52
+ UINT32 layer_proc_reg_52;
+
+
+ //REGISTER layer_proc_reg_53
+ UINT32 layer_proc_reg_53;
+
+
+ //REGISTER layer_proc_reg_54
+ UINT32 layer_proc_reg_54;
+
+
+ //REGISTER layer_proc_reg_55
+ UINT32 layer_proc_reg_55;
+
+
+ //REGISTER layer_proc_reg_56
+ UINT32 layer_proc_reg_56;
+
+
+ //REGISTER layer_proc_reg_57
+ UINT32 layer_proc_reg_57;
+
+
+ //REGISTER layer_proc_reg_58
+ UINT32 layer_proc_reg_58;
+
+
+ //REGISTER layer_proc_reg_59
+ UINT32 layer_proc_reg_59;
+
+
+ //REGISTER layer_proc_reg_60
+ UINT32 layer_proc_reg_60;
+
+
+ //REGISTER layer_proc_reg_61
+ UINT32 layer_proc_reg_61;
+
+
+ //REGISTER layer_proc_reg_62
+ UINT32 layer_proc_reg_62;
+
+
+ //REGISTER layer_proc_reg_63
+ UINT32 layer_proc_reg_63;
+
+
+ //REGISTER layer_proc_reg_64
+ UINT32 layer_proc_reg_64;
+
+
+ //REGISTER layer_proc_reg_65
+ UINT32 layer_proc_reg_65;
+
+
+ //REGISTER layer_proc_reg_66
+ UINT32 layer_proc_reg_66;
+
+
+ //REGISTER layer_proc_reg_67
+ UINT32 layer_proc_reg_67;
+
+
+ //REGISTER layer_proc_reg_68
+ UINT32 layer_proc_reg_68;
+
+
+ //REGISTER layer_proc_reg_69
+ UINT32 layer_proc_reg_69;
+
+
+ //REGISTER layer_proc_reg_70
+ UINT32 layer_proc_reg_70;
+
+
+ //REGISTER layer_proc_reg_71
+ UINT32 layer_proc_reg_71;
+
+
+ //REGISTER layer_proc_reg_72
+ UINT32 layer_proc_reg_72;
+
+
+ //REGISTER layer_proc_reg_73
+ UINT32 layer_proc_reg_73;
+
+
+ //REGISTER layer_proc_reg_74
+ UINT32 layer_proc_reg_74;
+
+
+ //REGISTER layer_proc_reg_75
+ UINT32 layer_proc_reg_75;
+
+
+ //REGISTER layer_proc_reg_76
+ UINT32 layer_proc_reg_76;
+
+
+ //REGISTER layer_proc_reg_77
+ UINT32 layer_proc_reg_77;
+
+
+ //REGISTER layer_proc_reg_78
+ UINT32 layer_proc_reg_78;
+
+
+ //REGISTER layer_proc_reg_79
+ UINT32 layer_proc_reg_79;
+
+
+ //REGISTER layer_proc_reg_80
+ UINT32 layer_proc_reg_80;
+
+
+ } v;
+
+ //INT32 value32[81];
+
+}PREPIPE_LAYER_PROC_X_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef RDMA_PATH_X_REG_H
+#define RDMA_PATH_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER LAYER_CTRL
+ UINT32 layer_mode : 2 ;
+ UINT32 outstanding_num : 5 ;
+ UINT32 req_conti_num : 5 ;
+ UINT32 layer_cmpsr_id : 3 ;
+ UINT32 axi_port_sel : 2 ;
+ UINT32 rdma_burst_len : 8 ;
+ UINT32 is_two_layers : 1 ;
+ UINT32 is_offline : 1 ;
+ UINT32 hdr_osd_num : 4 ;
+ UINT32 : 1 ;
+
+
+ //REGISTER COMPSR_Y_OFST
+ UINT32 compsr_y_offset0 : 16;
+ UINT32 : 16;
+
+
+ //REGISTER LEFT_SCL_RATIO_V
+ UINT32 : 32;
+
+
+ //REGISTER LEFT_INIT_PHASE_V_LOW
+ UINT32 : 32;
+
+
+ //REGISTER LEFT_INIT_PHASE_V_HIGH
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_SCL_RATIO_V
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_INIT_PHASE_V_LOW
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_INIT_PHASE_V_HIGH
+ UINT32 : 32;
+
+
+ //REGISTER LEFT_BASE_ADDR0_LOW
+ UINT32 base_addr0_low_ly0 : 32;
+
+
+ //REGISTER LEFT_BASE_ADDR0_HIGH
+ UINT32 base_addr0_high_ly0 : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER LEFT_BASE_ADDR1_LOW
+ UINT32 base_addr1_low_ly0 : 32;
+
+
+ //REGISTER LEFT_BASE_ADDR1_HIGH
+ UINT32 base_addr1_high_ly0 : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER LEFT_BASE_ADDR2_LOW
+ UINT32 base_addr2_low_ly0 : 32;
+
+
+ //REGISTER LEFT_BASE_ADDR2_HIGH
+ UINT32 base_addr2_high_ly0 : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER LEFT_RDMA_STRIDE0
+ UINT32 rdma_stride0_layer0 : 16;
+ UINT32 rdma_stride1_layer0 : 16;
+
+
+ //REGISTER LEFT_IMG_SIZE
+ UINT32 img_width_ly0 : 16;
+ UINT32 img_height_ly0 : 16;
+
+
+ //REGISTER LEFT_CROP_POS_START
+ UINT32 bbox_start_x_ly0 : 16;
+ UINT32 bbox_start_y_ly0 : 16;
+
+
+ //REGISTER LEFT_CROP_POS_END
+ UINT32 bbox_end_x_ly0 : 16;
+ UINT32 bbox_end_y_ly0 : 16;
+
+
+ //REGISTER RIGHT_BASE_ADDR0_LOW
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_BASE_ADDR0_HIGH
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_BASE_ADDR1_LOW
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_BASE_ADDR1_HIGH
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_BASE_ADDR2_LOW
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_BASE_ADDR2_HIGH
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_RDMA_STRIDE0
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_IMG_SIZE
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_CROP_POS_START
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_CROP_POS_END
+ UINT32 : 32;
+
+
+ //REGISTER ROT_MODE
+ UINT32 pixel_format : 6 ;
+ UINT32 uv_swap : 1 ;
+ UINT32 rot_mode_ly0 : 3 ;
+ UINT32 rot_mode_ly1 : 3 ;
+ UINT32 : 19;
+
+
+ //REGISTER AFBC_CFG
+ UINT32 fbc_split_mode : 1 ;
+ UINT32 fbc_yuv_transform : 1 ;
+ UINT32 fbc_sb_layout : 1 ;
+ UINT32 fbc_tile_type : 1 ;
+ UINT32 : 28;
+
+
+ //REGISTER FBC_MEM_SIZE
+ UINT32 fbc_mem_size : 16;
+ UINT32 fbc_mem_base_addr : 12;
+ UINT32 fbc_mem_map : 1 ;
+ UINT32 dec_line_num_sw : 1 ;
+ UINT32 sw_dec_line_nnum : 2 ;
+
+
+ //REGISTER LAYER_NSAID
+ UINT32 nsaid : 4 ;
+ UINT32 : 28;
+
+
+ //REGISTER CSC_MATRIX0
+ UINT32 csc_matrix00 : 14;
+ UINT32 csc_matrix01 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER CSC_MATRIX1
+ UINT32 csc_matrix02 : 14;
+ UINT32 csc_matrix03 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER CSC_MATRIX2
+ UINT32 csc_matrix10 : 14;
+ UINT32 csc_matrix11 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER CSC_MATRIX3
+ UINT32 csc_matrix12 : 14;
+ UINT32 csc_matrix13 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER CSC_MATRIX4
+ UINT32 csc_matrix20 : 14;
+ UINT32 csc_matrix21 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER CSC_MATRIX5
+ UINT32 csc_matrix22 : 14;
+ UINT32 csc_matrix23 : 14;
+ UINT32 : 4 ;
+
+
+ //REGISTER LEFT_ALPHA01
+ UINT32 alpha0_ly0 : 12;
+ UINT32 : 4 ;
+ UINT32 alpha1_ly0 : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER LEFT_ALPHA23
+ UINT32 alpha2_ly0 : 12;
+ UINT32 : 4 ;
+ UINT32 alpha3_ly0 : 12;
+ UINT32 : 4 ;
+
+
+ //REGISTER RIGHT_ALPHA01
+ UINT32 : 32;
+
+
+ //REGISTER RIGHT_ALPHA23
+ UINT32 : 32;
+
+
+ //REGISTER DBG_IRQ_RAW
+ UINT32 tlc_miss_irq_raw : 1 ;
+ UINT32 tbu_size_err_irq_raw : 1 ;
+ UINT32 mmu_rdma_timeout_raw : 1 ;
+ UINT32 mmu_rdma_rsp_decerr_raw : 1 ;
+ UINT32 mmu_rdma_rsp_slverr_raw : 1 ;
+ UINT32 mmu_rdma_rsp_exok_raw : 1 ;
+ UINT32 rdma_timeout_irq_raw : 1 ;
+ UINT32 rdma_rsp_decerr_raw : 1 ;
+ UINT32 rdma_rsp_slverr_raw : 1 ;
+ UINT32 rdma_rsp_exok_raw : 1 ;
+ UINT32 dma_mem_err_hw_raw : 1 ;
+ UINT32 rdma_eof_ly0_raw : 1 ;
+ UINT32 rdma_eof_ly1_raw : 1 ;
+ UINT32 rdma_output_eof_ly0_raw : 1 ;
+ UINT32 rdma_output_eof_ly1_raw : 1 ;
+ UINT32 fbcdec_eof_ly0_raw : 1 ;
+ UINT32 fbcdec_eof_ly1_raw : 1 ;
+ UINT32 fbcdec_err_ly0_raw : 1 ;
+ UINT32 fbcdec_err_ly1_raw : 1 ;
+ UINT32 rdma_all_out_eof_raw : 1 ;
+ UINT32 rmda_err_sw_raw : 1 ;
+ UINT32 mem_conflict_raw : 1 ;
+ UINT32 rdma_sof_raw : 1 ;
+ UINT32 rdma_va_mismatch_raw : 1 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER DBG_IRQ_MASK
+ UINT32 tlc_miss_irq_mask : 1 ;
+ UINT32 tbu_size_err_irq_mask : 1 ;
+ UINT32 mmu_rdma_timeout_mask : 1 ;
+ UINT32 mmu_rdma_rsp_decerr_mask : 1 ;
+ UINT32 mmu_rdma_rsp_slverr_mask : 1 ;
+ UINT32 mmu_rdma_rsp_exok_mask : 1 ;
+ UINT32 rdma_timeout_irq_mask : 1 ;
+ UINT32 rdma_rsp_decerr_mask : 1 ;
+ UINT32 rdma_rsp_slverr_mask : 1 ;
+ UINT32 rdma_rsp_exok_mask : 1 ;
+ UINT32 dma_mem_err_hw_mask : 1 ;
+ UINT32 rdma_eof_ly0_mask : 1 ;
+ UINT32 rdma_eof_ly1_mask : 1 ;
+ UINT32 rdma_output_eof_ly0_mask : 1 ;
+ UINT32 rdma_output_eof_ly1_mask : 1 ;
+ UINT32 fbcdec_eof_ly0_mask : 1 ;
+ UINT32 fbcdec_eof_ly1_mask : 1 ;
+ UINT32 fbcdec_err_ly0_mask : 1 ;
+ UINT32 fbcdec_err_ly1_mask : 1 ;
+ UINT32 rdma_all_out_eof_mask : 1 ;
+ UINT32 rdma_err_sw_mask : 1 ;
+ UINT32 mem_conflict_mask : 1 ;
+ UINT32 rdma_sof_mask : 1 ;
+ UINT32 rdma_va_mismatch_mask : 1 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER DBG_IRQ_STATUS
+ UINT32 tlc_miss_irq_status : 1 ;
+ UINT32 tbu_size_err_irq_status : 1 ;
+ UINT32 mmu_rdma_timeout_status : 1 ;
+ UINT32 mmu_rdma_rsp_decerr_status : 1 ;
+ UINT32 mmu_rdma_rsp_slverr_status : 1 ;
+ UINT32 mmu_rdma_rsp_exok_status : 1 ;
+ UINT32 rdma_timeout_irq_status : 1 ;
+ UINT32 rdma_rsp_decerr_status : 1 ;
+ UINT32 rdma_rsp_slverr_status : 1 ;
+ UINT32 rdma_rsp_exok_status : 1 ;
+ UINT32 dma_mem_err_status : 1 ;
+ UINT32 rdma_eof_ly0_status : 1 ;
+ UINT32 rdma_eof_ly1_status : 1 ;
+ UINT32 rdma_output_eof_ly0_status : 1 ;
+ UINT32 rdma_output_eof_ly1_status : 1 ;
+ UINT32 fbcdec_eof_ly0_status : 1 ;
+ UINT32 fbcdec_eof_ly1_status : 1 ;
+ UINT32 fbcdec_err_ly0_status : 1 ;
+ UINT32 fbcdec_err_ly1_status : 1 ;
+ UINT32 rdma_all_out_eof_status : 1 ;
+ UINT32 rdma_mem_err_sw : 1 ;
+ UINT32 mem_conflict_status : 1 ;
+ UINT32 rdma_eof_status : 1 ;
+ UINT32 rdma_va_mismatch_status : 1 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER PREFETCH_OSD_CTRL
+ UINT32 prefetch_osd_num : 5 ;
+ UINT32 prefetch_hdr_osd_num : 4 ;
+ UINT32 osd_sub_step : 2 ;
+ UINT32 osd_num_min : 5 ;
+ UINT32 hdr_osd_num_min : 4 ;
+ UINT32 pp_buf_switch_num : 3 ;
+ UINT32 : 9 ;
+ } b;
+
+ struct
+ {
+ //REGISTER LAYER_CTRL
+ UINT32 LAYER_CTRL;
+
+
+ //REGISTER COMPSR_Y_OFST
+ UINT32 COMPSR_Y_OFST;
+
+
+ //REGISTER LEFT_SCL_RATIO_V
+ UINT32 LEFT_SCL_RATIO_V;
+
+
+ //REGISTER LEFT_INIT_PHASE_V_LOW
+ UINT32 LEFT_INIT_PHASE_V_LOW;
+
+
+ //REGISTER LEFT_INIT_PHASE_V_HIGH
+ UINT32 LEFT_INIT_PHASE_V_HIGH;
+
+
+ //REGISTER RIGHT_SCL_RATIO_V
+ UINT32 RIGHT_SCL_RATIO_V;
+
+
+ //REGISTER RIGHT_INIT_PHASE_V_LOW
+ UINT32 RIGHT_INIT_PHASE_V_LOW;
+
+
+ //REGISTER RIGHT_INIT_PHASE_V_HIGH
+ UINT32 RIGHT_INIT_PHASE_V_HIGH;
+
+
+ //REGISTER LEFT_BASE_ADDR0_LOW
+ UINT32 LEFT_BASE_ADDR0_LOW;
+
+
+ //REGISTER LEFT_BASE_ADDR0_HIGH
+ UINT32 LEFT_BASE_ADDR0_HIGH;
+
+
+ //REGISTER LEFT_BASE_ADDR1_LOW
+ UINT32 LEFT_BASE_ADDR1_LOW;
+
+
+ //REGISTER LEFT_BASE_ADDR1_HIGH
+ UINT32 LEFT_BASE_ADDR1_HIGH;
+
+
+ //REGISTER LEFT_BASE_ADDR2_LOW
+ UINT32 LEFT_BASE_ADDR2_LOW;
+
+
+ //REGISTER LEFT_BASE_ADDR2_HIGH
+ UINT32 LEFT_BASE_ADDR2_HIGH;
+
+
+ //REGISTER LEFT_RDMA_STRIDE0
+ UINT32 LEFT_RDMA_STRIDE0;
+
+
+ //REGISTER LEFT_IMG_SIZE
+ UINT32 LEFT_IMG_SIZE;
+
+
+ //REGISTER LEFT_CROP_POS_START
+ UINT32 LEFT_CROP_POS_START;
+
+
+ //REGISTER LEFT_CROP_POS_END
+ UINT32 LEFT_CROP_POS_END;
+
+
+ //REGISTER RIGHT_BASE_ADDR0_LOW
+ UINT32 RIGHT_BASE_ADDR0_LOW;
+
+
+ //REGISTER RIGHT_BASE_ADDR0_HIGH
+ UINT32 RIGHT_BASE_ADDR0_HIGH;
+
+
+ //REGISTER RIGHT_BASE_ADDR1_LOW
+ UINT32 RIGHT_BASE_ADDR1_LOW;
+
+
+ //REGISTER RIGHT_BASE_ADDR1_HIGH
+ UINT32 RIGHT_BASE_ADDR1_HIGH;
+
+
+ //REGISTER RIGHT_BASE_ADDR2_LOW
+ UINT32 RIGHT_BASE_ADDR2_LOW;
+
+
+ //REGISTER RIGHT_BASE_ADDR2_HIGH
+ UINT32 RIGHT_BASE_ADDR2_HIGH;
+
+
+ //REGISTER RIGHT_RDMA_STRIDE0
+ UINT32 RIGHT_RDMA_STRIDE0;
+
+
+ //REGISTER RIGHT_IMG_SIZE
+ UINT32 RIGHT_IMG_SIZE;
+
+
+ //REGISTER RIGHT_CROP_POS_START
+ UINT32 RIGHT_CROP_POS_START;
+
+
+ //REGISTER RIGHT_CROP_POS_END
+ UINT32 RIGHT_CROP_POS_END;
+
+
+ //REGISTER ROT_MODE
+ UINT32 ROT_MODE;
+
+
+ //REGISTER AFBC_CFG
+ UINT32 AFBC_CFG;
+
+
+ //REGISTER FBC_MEM_SIZE
+ UINT32 FBC_MEM_SIZE;
+
+
+ //REGISTER LAYER_NSAID
+ UINT32 LAYER_NSAID;
+
+
+ //REGISTER CSC_MATRIX0
+ UINT32 CSC_MATRIX0;
+
+
+ //REGISTER CSC_MATRIX1
+ UINT32 CSC_MATRIX1;
+
+
+ //REGISTER CSC_MATRIX2
+ UINT32 CSC_MATRIX2;
+
+
+ //REGISTER CSC_MATRIX3
+ UINT32 CSC_MATRIX3;
+
+
+ //REGISTER CSC_MATRIX4
+ UINT32 CSC_MATRIX4;
+
+
+ //REGISTER CSC_MATRIX5
+ UINT32 CSC_MATRIX5;
+
+
+ //REGISTER LEFT_ALPHA01
+ UINT32 LEFT_ALPHA01;
+
+
+ //REGISTER LEFT_ALPHA23
+ UINT32 LEFT_ALPHA23;
+
+
+ //REGISTER RIGHT_ALPHA01
+ UINT32 RIGHT_ALPHA01;
+
+
+ //REGISTER RIGHT_ALPHA23
+ UINT32 RIGHT_ALPHA23;
+
+
+ //REGISTER DBG_IRQ_RAW
+ UINT32 DBG_IRQ_RAW;
+
+
+ //REGISTER DBG_IRQ_MASK
+ UINT32 DBG_IRQ_MASK;
+
+
+ //REGISTER DBG_IRQ_STATUS
+ UINT32 DBG_IRQ_STATUS;
+
+
+ //PREFETCH_OSD_CTRL
+ UINT32 PREFETCH_OSD_CTRL;
+ } v;
+
+
+// INT32 value32[46];
+
+}RDMA_PATH_X_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SATURN_REG_MAP_A0_H_
+#define _SATURN_REG_MAP_A0_H_
+
+#ifndef UINT32
+typedef uint32_t UINT32;
+#endif
+
+#ifndef INT32
+typedef uint32_t INT32;
+#endif
+
+#define SATURN_BASE_ADDR 0x0
+
+#define DPU_TOP_BASE_ADDR 0x0
+#define DPU_CTRL_BASE_ADDR 0x500
+#define DPU_CRG_BASE_ADDR 0x700
+#define CMDLIST_BASE_ADDR 0x800
+#define DPU_INT_BASE_ADDR 0x900
+
+#define RDMA_SIZE 0x100
+#define DMA_TOP_BASE_ADDR 0xA00
+#define RDMA0_BASE_ADDR (DMA_TOP_BASE_ADDR + 0x80)
+#define RDMA1_BASE_ADDR (RDMA0_BASE_ADDR + RDMA_SIZE)
+#define RDMA2_BASE_ADDR (RDMA1_BASE_ADDR + RDMA_SIZE)
+#define RDMA3_BASE_ADDR (RDMA2_BASE_ADDR + RDMA_SIZE)
+#define RDMA4_BASE_ADDR (RDMA3_BASE_ADDR + RDMA_SIZE)
+#define RDMA5_BASE_ADDR (RDMA4_BASE_ADDR + RDMA_SIZE)
+#define RDMA6_BASE_ADDR (RDMA5_BASE_ADDR + RDMA_SIZE)
+#define RDMA7_BASE_ADDR (RDMA6_BASE_ADDR + RDMA_SIZE)
+#define RDMA8_BASE_ADDR (RDMA7_BASE_ADDR + RDMA_SIZE)
+#define RDMA9_BASE_ADDR (RDMA8_BASE_ADDR + RDMA_SIZE)
+#define RDMA10_BASE_ADDR (RDMA9_BASE_ADDR + RDMA_SIZE)
+#define RDMA11_BASE_ADDR (RDMA10_BASE_ADDR + RDMA_SIZE)
+#define RDMA_BASE_ADDR(rdma_id) (RDMA0_BASE_ADDR + rdma_id * RDMA_SIZE)
+
+#define MMU_TBU_SIZE 0x40
+#define MMU_TOP_SIZE 0x100
+#define MMU_BASE_ADDR (RDMA11_BASE_ADDR + RDMA_SIZE)
+#define MMU_TOP_BASE_ADDR (MMU_BASE_ADDR)
+#define MMU_TBU_BASE_ADDR (MMU_BASE_ADDR + 0x100)
+
+#define LP_SIZE 0x300
+#define LMERGE_SIZE 0x20
+#define LP0_BASE_ADDR 0x2000
+#define LP1_BASE_ADDR (LP0_BASE_ADDR + LP_SIZE)
+#define LP2_BASE_ADDR (LP1_BASE_ADDR + LP_SIZE)
+#define LP3_BASE_ADDR (LP2_BASE_ADDR + LP_SIZE)
+#define LP4_BASE_ADDR (LP3_BASE_ADDR + LP_SIZE)
+#define LP5_BASE_ADDR (LP4_BASE_ADDR + LP_SIZE)
+#define LP6_BASE_ADDR (LP5_BASE_ADDR + LP_SIZE)
+#define LP7_BASE_ADDR (LP6_BASE_ADDR + LP_SIZE)
+#define LP8_BASE_ADDR (LP7_BASE_ADDR + LP_SIZE)
+#define LP9_BASE_ADDR (LP8_BASE_ADDR + LP_SIZE)
+#define LP10_BASE_ADDR (LP9_BASE_ADDR + LP_SIZE)
+#define LP11_BASE_ADDR (LP10_BASE_ADDR + LP_SIZE)
+#define LMERGE0_BASE_ADDR (LP11_BASE_ADDR + LP_SIZE)
+#define LMERGE1_BASE_ADDR (LMERGE0_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE2_BASE_ADDR (LMERGE1_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE3_BASE_ADDR (LMERGE2_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE4_BASE_ADDR (LMERGE3_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE5_BASE_ADDR (LMERGE4_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE6_BASE_ADDR (LMERGE5_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE7_BASE_ADDR (LMERGE6_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE8_BASE_ADDR (LMERGE7_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE9_BASE_ADDR (LMERGE8_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE10_BASE_ADDR (LMERGE9_BASE_ADDR + LMERGE_SIZE)
+#define LMERGE11_BASE_ADDR (LMERGE10_BASE_ADDR + LMERGE_SIZE)
+
+#define CMP_SIZE 0x300
+#define CMP0_BASE_ADDR 0x4600
+#define CMP1_BASE_ADDR (CMP0_BASE_ADDR + CMP_SIZE)
+#define CMP2_BASE_ADDR (CMP1_BASE_ADDR + CMP_SIZE)
+#define CMP3_BASE_ADDR (CMP2_BASE_ADDR + CMP_SIZE)
+#define CMP_BASE_ADDR(cmp_id) (CMP0_BASE_ADDR + cmp_id * CMP_SIZE)
+
+#define SCALER_SIZE 0x200
+#define SCALER0_ONLINE_BASE_ADDR 0x6000
+#define SCALER1_ONLINE_BASE_ADDR (SCALER0_ONLINE_BASE_ADDR + SCALER_SIZE)
+
+#define OUTCTRL_SIZE 0x8800
+#define OUTCTRL0_BASE_ADDR 0x7000
+#define PP0_BASE_ADDR (OUTCTRL0_BASE_ADDR + 0x100)
+#define ACAD0_BASE_ADDR (OUTCTRL0_BASE_ADDR + 0x280)
+#define LUT3D0_BASE_ADDR (OUTCTRL0_BASE_ADDR + 0x600)
+#define DSCA0_BASE_ADDR (OUTCTRL0_BASE_ADDR + 0x8000)
+#define DSCB0_BASE_ADDR (OUTCTRL0_BASE_ADDR + 0x8100)
+
+#define OUTCTRL1_BASE_ADDR (OUTCTRL0_BASE_ADDR + OUTCTRL_SIZE)
+#define PP1_BASE_ADDR (OUTCTRL1_BASE_ADDR + 0x100)
+#define ACAD1_BASE_ADDR (OUTCTRL1_BASE_ADDR + 0x280)
+#define LUT3D1_BASE_ADDR (OUTCTRL1_BASE_ADDR + 0x600)
+#define DSCA1_BASE_ADDR (OUTCTRL1_BASE_ADDR + 0x8000)
+#define DSCB1_BASE_ADDR (OUTCTRL1_BASE_ADDR + 0x8100)
+
+#define OUTCTRL2_BASE_ADDR (OUTCTRL1_BASE_ADDR + OUTCTRL_SIZE)
+#define PP2_BASE_ADDR (OUTCTRL2_BASE_ADDR + 0x100)
+#define ACAD2_BASE_ADDR (OUTCTRL2_BASE_ADDR + 0x280)
+#define LUT3D2_BASE_ADDR (OUTCTRL2_BASE_ADDR + 0x600)
+#define DSCA2_BASE_ADDR (OUTCTRL2_BASE_ADDR + 0x8000)
+#define DSCB2_BASE_ADDR (OUTCTRL2_BASE_ADDR + 0x8100)
+
+#define OUTCTRL3_BASE_ADDR (OUTCTRL2_BASE_ADDR + OUTCTRL_SIZE)
+#define PP3_BASE_ADDR (OUTCTRL3_BASE_ADDR + 0x100)
+#define ACAD3_BASE_ADDR (OUTCTRL3_BASE_ADDR + 0x280)
+#define LUT3D3_BASE_ADDR (OUTCTRL3_BASE_ADDR + 0x600)
+#define DSCA3_BASE_ADDR (OUTCTRL3_BASE_ADDR + 0x8000)
+#define DSCB3_BASE_ADDR (OUTCTRL3_BASE_ADDR + 0x8100)
+#define OUTCTRL_BASE_ADDR(ctrl_id) (OUTCTRL0_BASE_ADDR + OUTCTRL_SIZE * ctrl_id)
+
+#define WB_SIZE 0x400
+#define WB0_TOP_BASE_ADDR 0x29000
+#define WB0_SCALER_BASE_ADDR (WB0_TOP_BASE_ADDR + 0x200)
+#define WB1_TOP_BASE_ADDR (WB0_TOP_BASE_ADDR + WB_SIZE)
+#define WB1_SCALER_BASE_ADDR (WB1_TOP_BASE_ADDR + 0x200)
+
+#define SATURN_SIZE 0x2A000
+
+#include "cmdlist.h"
+#include "cmps_x.h"
+#include "dma_top.h"
+#include "dpu_crg.h"
+#include "dpu_ctl.h"
+#include "dpu_intp.h"
+#include "dpu_top.h"
+#include "mmu.h"
+#include "outctrl_top_x.h"
+#include "outctrl_proc_x.h"
+#include "rdma_path_x.h"
+#include "scaler_x.h"
+#include "wb_top.h"
+#include "prepipe_layer_proc_x.h"
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef SCALER_X_REG_H
+#define SCALER_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER disp_scl_reg_0
+ UINT32 m_nscl_hor_enable : 1 ;
+ UINT32 m_nscl_ver_enable : 1 ;
+ UINT32 : 6 ;
+ UINT32 m_nscl_input_width : 16;
+ UINT32 : 8 ;
+
+
+ //REGISTER disp_scl_reg_1
+ UINT32 m_nscl_input_height : 16;
+ UINT32 m_nscl_output_width : 16;
+
+
+ //REGISTER disp_scl_reg_2
+ UINT32 m_nscl_output_height : 16;
+ UINT32 : 16;
+
+
+ //REGISTER disp_scl_reg_3
+ UINT32 m_nscl_hor_init_phase_l32b : 32;
+
+
+ //REGISTER disp_scl_reg_4
+ UINT32 m_nscl_hor_init_phase_h1b : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER disp_scl_reg_5
+ UINT32 m_nscl_ver_init_phase_l32b : 32;
+
+
+ //REGISTER disp_scl_reg_6
+ UINT32 m_nscl_ver_init_phase_h1b : 1 ;
+ UINT32 : 31;
+
+
+ //REGISTER disp_scl_reg_7
+ UINT32 m_nscl_hor_delta_phase : 20;
+ UINT32 : 12;
+
+
+ //REGISTER disp_scl_reg_8
+ UINT32 m_nscl_ver_delta_phase : 20;
+ UINT32 : 12;
+
+
+ //REGISTER disp_scl_reg_9
+ UINT32 m_nscl_hor_coef0 : 16;
+ UINT32 m_nscl_hor_coef1 : 16;
+
+
+ //REGISTER disp_scl_reg_10
+ UINT32 m_nscl_hor_coef2 : 16;
+ UINT32 m_nscl_hor_coef3 : 16;
+
+
+ //REGISTER disp_scl_reg_11
+ UINT32 m_nscl_hor_coef4 : 16;
+ UINT32 m_nscl_hor_coef5 : 16;
+
+
+ //REGISTER disp_scl_reg_12
+ UINT32 m_nscl_hor_coef6 : 16;
+ UINT32 m_nscl_hor_coef7 : 16;
+
+
+ //REGISTER disp_scl_reg_13
+ UINT32 m_nscl_hor_coef8 : 16;
+ UINT32 m_nscl_hor_coef9 : 16;
+
+
+ //REGISTER disp_scl_reg_14
+ UINT32 m_nscl_hor_coef10 : 16;
+ UINT32 m_nscl_hor_coef11 : 16;
+
+
+ //REGISTER disp_scl_reg_15
+ UINT32 m_nscl_hor_coef12 : 16;
+ UINT32 m_nscl_hor_coef13 : 16;
+
+
+ //REGISTER disp_scl_reg_16
+ UINT32 m_nscl_hor_coef14 : 16;
+ UINT32 m_nscl_hor_coef15 : 16;
+
+
+ //REGISTER disp_scl_reg_17
+ UINT32 m_nscl_hor_coef16 : 16;
+ UINT32 m_nscl_hor_coef17 : 16;
+
+
+ //REGISTER disp_scl_reg_18
+ UINT32 m_nscl_hor_coef18 : 16;
+ UINT32 m_nscl_hor_coef19 : 16;
+
+
+ //REGISTER disp_scl_reg_19
+ UINT32 m_nscl_hor_coef20 : 16;
+ UINT32 m_nscl_hor_coef21 : 16;
+
+
+ //REGISTER disp_scl_reg_20
+ UINT32 m_nscl_hor_coef22 : 16;
+ UINT32 m_nscl_hor_coef23 : 16;
+
+
+ //REGISTER disp_scl_reg_21
+ UINT32 m_nscl_hor_coef24 : 16;
+ UINT32 m_nscl_hor_coef25 : 16;
+
+
+ //REGISTER disp_scl_reg_22
+ UINT32 m_nscl_hor_coef26 : 16;
+ UINT32 m_nscl_hor_coef27 : 16;
+
+
+ //REGISTER disp_scl_reg_23
+ UINT32 m_nscl_hor_coef28 : 16;
+ UINT32 m_nscl_hor_coef29 : 16;
+
+
+ //REGISTER disp_scl_reg_24
+ UINT32 m_nscl_hor_coef30 : 16;
+ UINT32 m_nscl_hor_coef31 : 16;
+
+
+ //REGISTER disp_scl_reg_25
+ UINT32 m_nscl_hor_coef32 : 16;
+ UINT32 m_nscl_hor_coef33 : 16;
+
+
+ //REGISTER disp_scl_reg_26
+ UINT32 m_nscl_hor_coef34 : 16;
+ UINT32 m_nscl_hor_coef35 : 16;
+
+
+ //REGISTER disp_scl_reg_27
+ UINT32 m_nscl_hor_coef36 : 16;
+ UINT32 m_nscl_hor_coef37 : 16;
+
+
+ //REGISTER disp_scl_reg_28
+ UINT32 m_nscl_hor_coef38 : 16;
+ UINT32 m_nscl_hor_coef39 : 16;
+
+
+ //REGISTER disp_scl_reg_29
+ UINT32 m_nscl_hor_coef40 : 16;
+ UINT32 m_nscl_hor_coef41 : 16;
+
+
+ //REGISTER disp_scl_reg_30
+ UINT32 m_nscl_hor_coef42 : 16;
+ UINT32 m_nscl_hor_coef43 : 16;
+
+
+ //REGISTER disp_scl_reg_31
+ UINT32 m_nscl_hor_coef44 : 16;
+ UINT32 m_nscl_hor_coef45 : 16;
+
+
+ //REGISTER disp_scl_reg_32
+ UINT32 m_nscl_hor_coef46 : 16;
+ UINT32 m_nscl_hor_coef47 : 16;
+
+
+ } b;
+
+ struct
+ {
+ UINT32 disp_scl_reg_0;
+ UINT32 disp_scl_reg_1;
+ UINT32 disp_scl_reg_2;
+ UINT32 disp_scl_reg_3;
+ UINT32 disp_scl_reg_4;
+ UINT32 disp_scl_reg_5;
+ UINT32 disp_scl_reg_6;
+ UINT32 disp_scl_reg_7;
+ UINT32 disp_scl_reg_8;
+ UINT32 disp_scl_reg_9;
+ UINT32 disp_scl_reg_10;
+ UINT32 disp_scl_reg_11;
+ UINT32 disp_scl_reg_12;
+ UINT32 disp_scl_reg_13;
+ UINT32 disp_scl_reg_14;
+ UINT32 disp_scl_reg_15;
+ UINT32 disp_scl_reg_16;
+ UINT32 disp_scl_reg_17;
+ UINT32 disp_scl_reg_18;
+ UINT32 disp_scl_reg_19;
+ UINT32 disp_scl_reg_20;
+ UINT32 disp_scl_reg_21;
+ UINT32 disp_scl_reg_22;
+ UINT32 disp_scl_reg_23;
+ UINT32 disp_scl_reg_24;
+ UINT32 disp_scl_reg_25;
+ UINT32 disp_scl_reg_26;
+ UINT32 disp_scl_reg_27;
+ UINT32 disp_scl_reg_28;
+ UINT32 disp_scl_reg_29;
+ UINT32 disp_scl_reg_30;
+ UINT32 disp_scl_reg_31;
+ UINT32 disp_scl_reg_32;
+ } v;
+
+}SCALER_X_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef WB_TOP_X_REG_H
+#define WB_TOP_X_REG_H
+
+typedef union
+{
+ struct
+ {
+ //REGISTER wb_top_reg_0
+ UINT32 wb_in_crop_en : 1 ;
+ UINT32 m_nwb_proc_en : 1 ;
+ UINT32 m_nmatrix_en : 1 ;
+ UINT32 m_noetf_en : 1 ;
+ UINT32 wb_en : 1 ;
+ UINT32 wb_scl_en : 1 ;
+ UINT32 : 2 ;
+ UINT32 wb_rot_mode : 3 ;
+ UINT32 wb_wdma_fbc_en : 1 ;
+ UINT32 rsvd_unuse : 1 ;
+ UINT32 : 3 ;
+ UINT32 wb_out_format : 5 ;
+ UINT32 : 11;
+
+
+ //REGISTER wb_top_reg_1
+ UINT32 wb_in_height : 16;
+ UINT32 wb_in_width : 16;
+
+
+ //REGISTER wb_top_reg_2
+ UINT32 wb_out_ori_height : 16;
+ UINT32 wb_out_ori_width : 16;
+
+
+ //REGISTER wb_top_reg_3
+ UINT32 wb_out_crop_ltopx : 16;
+ UINT32 wb_out_crop_ltopy : 16;
+
+
+ //REGISTER wb_top_reg_4
+ UINT32 wb_out_crop_height : 16;
+ UINT32 wb_out_crop_width : 16;
+
+
+ //REGISTER wb_top_reg_5
+ UINT32 wb_wdma_base_addr0_low : 32;
+
+
+ //REGISTER wb_top_reg_6
+ UINT32 wb_wdma_base_addr0_high : 2 ;
+ UINT32 : 30;
+
+
+ //REGISTER wb_top_reg_7
+ UINT32 wb_wdma_base_addr1_low : 32;
+
+
+ //REGISTER wb_top_reg_8
+ UINT32 wb_wdma_base_addr1_high : 2 ;
+ UINT32 : 6 ;
+ UINT32 wb_wdma_stride : 16;
+ UINT32 wb_wdma_outstanding_num : 5 ;
+ UINT32 : 3 ;
+
+
+ //REGISTER wb_top_reg_9
+ UINT32 wb_wdma_burst_len : 5 ;
+ UINT32 wb_wdma_axi_port : 2 ;
+ UINT32 : 5 ;
+ UINT32 wb_wdma_cache : 4 ;
+ UINT32 wb_wdma_region : 4 ;
+ UINT32 wb_wdma_qos : 4 ;
+ UINT32 : 8 ;
+
+
+ //REGISTER wb_top_reg_10
+ UINT32 copy_mode_enable : 1 ;
+ UINT32 default_color_enable : 1 ;
+ UINT32 yuv_transform_en : 1 ;
+ UINT32 fbc_split_en : 1 ;
+ UINT32 fbc_tile_hd_mode_en : 1 ;
+ UINT32 : 27;
+
+
+ //REGISTER wb_top_reg_11
+ UINT32 fmt_cvt_A0 : 16;
+ UINT32 fmt_cvt_A1 : 16;
+
+
+ //REGISTER wb_top_reg_12
+ UINT32 fmt_cvt_A2 : 16;
+ UINT32 fmt_cvt_narrow_mode : 1 ;
+ UINT32 : 15;
+
+
+ //REGISTER wb_top_reg_13
+ UINT32 fmt_cvt_matrix00 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix01 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_14
+ UINT32 fmt_cvt_matrix02 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix03 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_15
+ UINT32 fmt_cvt_matrix10 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix11 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_16
+ UINT32 fmt_cvt_matrix12 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix13 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_17
+ UINT32 fmt_cvt_matrix20 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix21 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_18
+ UINT32 fmt_cvt_matrix22 : 14;
+ UINT32 : 2 ;
+ UINT32 fmt_cvt_matrix23 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_19
+ UINT32 wb_dither_en : 1 ;
+ UINT32 wb_dither_auto_temp_en : 1 ;
+ UINT32 wb_dither_rot_mode : 2 ;
+ UINT32 wb_dither_mode : 1 ;
+ UINT32 : 3 ;
+ UINT32 wb_dither_out_dpth0 : 4 ;
+ UINT32 wb_dither_out_dpth1 : 4 ;
+ UINT32 wb_dither_out_dpth2 : 4 ;
+ UINT32 : 4 ;
+ UINT32 wb_dither_tmp_value : 8 ;
+
+
+ //REGISTER wb_top_reg_20
+ UINT32 wb_dither_pattern_bits : 3 ;
+ UINT32 : 29;
+
+
+ //REGISTER wb_top_reg_21
+ UINT32 wb_dither_bayer_map0 : 8 ;
+ UINT32 wb_dither_bayer_map1 : 8 ;
+ UINT32 wb_dither_bayer_map2 : 8 ;
+ UINT32 wb_dither_bayer_map3 : 8 ;
+
+
+ //REGISTER wb_top_reg_22
+ UINT32 wb_dither_bayer_map4 : 8 ;
+ UINT32 wb_dither_bayer_map5 : 8 ;
+ UINT32 wb_dither_bayer_map6 : 8 ;
+ UINT32 wb_dither_bayer_map7 : 8 ;
+
+
+ //REGISTER wb_top_reg_23
+ UINT32 wb_dither_bayer_map8 : 8 ;
+ UINT32 wb_dither_bayer_map9 : 8 ;
+ UINT32 wb_dither_bayer_map10 : 8 ;
+ UINT32 wb_dither_bayer_map11 : 8 ;
+
+
+ //REGISTER wb_top_reg_24
+ UINT32 wb_dither_bayer_map12 : 8 ;
+ UINT32 wb_dither_bayer_map13 : 8 ;
+ UINT32 wb_dither_bayer_map14 : 8 ;
+ UINT32 wb_dither_bayer_map15 : 8 ;
+
+
+ //REGISTER wb_top_reg_25
+ UINT32 wb_dither_bayer_map16 : 8 ;
+ UINT32 wb_dither_bayer_map17 : 8 ;
+ UINT32 wb_dither_bayer_map18 : 8 ;
+ UINT32 wb_dither_bayer_map19 : 8 ;
+
+
+ //REGISTER wb_top_reg_26
+ UINT32 wb_dither_bayer_map20 : 8 ;
+ UINT32 wb_dither_bayer_map21 : 8 ;
+ UINT32 wb_dither_bayer_map22 : 8 ;
+ UINT32 wb_dither_bayer_map23 : 8 ;
+
+
+ //REGISTER wb_top_reg_27
+ UINT32 wb_dither_bayer_map24 : 8 ;
+ UINT32 wb_dither_bayer_map25 : 8 ;
+ UINT32 wb_dither_bayer_map26 : 8 ;
+ UINT32 wb_dither_bayer_map27 : 8 ;
+
+
+ //REGISTER wb_top_reg_28
+ UINT32 wb_dither_bayer_map28 : 8 ;
+ UINT32 wb_dither_bayer_map29 : 8 ;
+ UINT32 wb_dither_bayer_map30 : 8 ;
+ UINT32 wb_dither_bayer_map31 : 8 ;
+
+
+ //REGISTER wb_top_reg_29
+ UINT32 wb_dither_bayer_map32 : 8 ;
+ UINT32 wb_dither_bayer_map33 : 8 ;
+ UINT32 wb_dither_bayer_map34 : 8 ;
+ UINT32 wb_dither_bayer_map35 : 8 ;
+
+
+ //REGISTER wb_top_reg_30
+ UINT32 wb_dither_bayer_map36 : 8 ;
+ UINT32 wb_dither_bayer_map37 : 8 ;
+ UINT32 wb_dither_bayer_map38 : 8 ;
+ UINT32 wb_dither_bayer_map39 : 8 ;
+
+
+ //REGISTER wb_top_reg_31
+ UINT32 wb_dither_bayer_map40 : 8 ;
+ UINT32 wb_dither_bayer_map41 : 8 ;
+ UINT32 wb_dither_bayer_map42 : 8 ;
+ UINT32 wb_dither_bayer_map43 : 8 ;
+
+
+ //REGISTER wb_top_reg_32
+ UINT32 wb_dither_bayer_map44 : 8 ;
+ UINT32 wb_dither_bayer_map45 : 8 ;
+ UINT32 wb_dither_bayer_map46 : 8 ;
+ UINT32 wb_dither_bayer_map47 : 8 ;
+
+
+ //REGISTER wb_top_reg_33
+ UINT32 wb_dither_bayer_map48 : 8 ;
+ UINT32 wb_dither_bayer_map49 : 8 ;
+ UINT32 wb_dither_bayer_map50 : 8 ;
+ UINT32 wb_dither_bayer_map51 : 8 ;
+
+
+ //REGISTER wb_top_reg_34
+ UINT32 wb_dither_bayer_map52 : 8 ;
+ UINT32 wb_dither_bayer_map53 : 8 ;
+ UINT32 wb_dither_bayer_map54 : 8 ;
+ UINT32 wb_dither_bayer_map55 : 8 ;
+
+
+ //REGISTER wb_top_reg_35
+ UINT32 wb_dither_bayer_map56 : 8 ;
+ UINT32 wb_dither_bayer_map57 : 8 ;
+ UINT32 wb_dither_bayer_map58 : 8 ;
+ UINT32 wb_dither_bayer_map59 : 8 ;
+
+
+ //REGISTER wb_top_reg_36
+ UINT32 wb_dither_bayer_map60 : 8 ;
+ UINT32 wb_dither_bayer_map61 : 8 ;
+ UINT32 wb_dither_bayer_map62 : 8 ;
+ UINT32 wb_dither_bayer_map63 : 8 ;
+
+
+ //REGISTER wb_top_reg_37
+ UINT32 wb_in_crop_ltopx : 16;
+ UINT32 wb_in_crop_ltopy : 16;
+
+
+ //REGISTER wb_top_reg_38
+ UINT32 wb_in_crop_rbotx : 16;
+ UINT32 wb_in_crop_rboty : 16;
+
+
+ //REGISTER wb_top_reg_39
+ UINT32 m_noetf_mode : 3 ;
+ UINT32 : 5 ;
+ UINT32 m_noetf_max : 12;
+ UINT32 : 12;
+
+
+ //REGISTER wb_top_reg_40
+ UINT32 m_pmatrix_table0 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table1 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_41
+ UINT32 m_pmatrix_table2 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table3 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_42
+ UINT32 m_pmatrix_table4 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table5 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_43
+ UINT32 m_pmatrix_table6 : 14;
+ UINT32 : 2 ;
+ UINT32 m_pmatrix_table7 : 14;
+ UINT32 : 2 ;
+
+
+ //REGISTER wb_top_reg_44
+ UINT32 m_pmatrix_table8 : 14;
+ UINT32 : 18;
+
+
+ //REGISTER wb_top_reg_45
+ UINT32 m_pmatrix_offset0 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER wb_top_reg_46
+ UINT32 m_pmatrix_offset1 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER wb_top_reg_47
+ UINT32 m_pmatrix_offset2 : 25;
+ UINT32 : 7 ;
+
+
+ //REGISTER wb_top_reg_48
+ UINT32 dbug_bus0 : 32;
+
+
+ //REGISTER wb_top_reg_49
+ UINT32 dbug_bus1 : 32;
+
+
+ //REGISTER wb_top_reg_50
+ UINT32 dbug_bus2 : 32;
+
+
+ //REGISTER wb_top_reg_51
+ UINT32 dbug_bus3 : 32;
+
+
+ //REGISTER wb_top_reg_52
+ UINT32 dbug_bus4 : 32;
+
+
+ //REGISTER wb_top_reg_53
+ UINT32 dbug_bus5 : 32;
+
+
+ //REGISTER wb_top_reg_54
+ UINT32 wb_wdma_nsaid : 4 ;
+ UINT32 : 28;
+
+
+ };
+
+ INT32 value32[55];
+
+}WB_TOP_REG;
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_device.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+#include "spacemit_dptc_drv.h"
+
+#define I2C_NO 0
+#define TOP_SLAVE_ADDR 0x30
+#define DSI_SLAVE_ADDR 0x33
+
+#ifdef DPTC_DPHY_TEST
+
+static struct twsi_data dptc_i2c_data;
+static DEFINE_MUTEX(cmd_mutex);
+
+static int twsi_write_i2c(struct twsi_data *data)
+{
+ int ret = 0;
+ struct i2c_adapter *adapter;
+ struct i2c_msg msg;
+ u8 val[8];
+ int i ,j =0;
+
+ if (!data || !data->addr || !data->reg_len || !data->val_len) {
+ pr_err("Error: %s, %d", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ msg.addr = data->addr;
+ msg.flags = 0;
+ msg.len = data->reg_len + data->val_len;
+ msg.buf = val;
+
+ adapter = i2c_get_adapter(data->twsi_no);
+ if (adapter == NULL)
+ return -1;
+
+ mutex_lock(&cmd_mutex);
+ for (i = 0; i < data->reg_len; i++)
+ val[j++]=((u8*)(&data->reg))[i];
+ for (i = 0; i < data->val_len; i++)
+ val[j++]=((u8*)(&data->val))[i];
+ ret = i2c_transfer(adapter, &msg, 1);
+ if (ret < 0) {
+ mutex_unlock(&cmd_mutex);
+ return ret;
+ }
+ mutex_unlock(&cmd_mutex);
+
+ return ret;
+}
+
+static int twsi_read_i2c(struct twsi_data *data)
+{
+ struct i2c_adapter *adapter;
+ struct i2c_msg msg;
+ int ret = 0;
+ u8 val[4];
+
+ if (!data || !data->addr || !data->reg_len || !data->val_len) {
+ pr_err("%s, error param", __func__);
+ return -EINVAL;
+ }
+
+ msg.addr = data->addr;
+ msg.flags = 0;
+ msg.len = data->reg_len;
+ msg.buf = val;
+
+ adapter = i2c_get_adapter(data->twsi_no);
+ if (adapter == NULL)
+ return -1;
+
+ mutex_lock(&cmd_mutex);
+ if (data->reg_len == I2C_8BIT)
+ val[0] = data->reg & 0xff;
+ else if (data->reg_len == I2C_16BIT) {
+ val[0] = (data->reg >> 8) & 0xff;
+ val[1] = data->reg & 0xff;
+ }
+ msg.len = data->reg_len;
+ ret = i2c_transfer(adapter, &msg, 1);
+ if (ret < 0) {
+ mutex_unlock(&cmd_mutex);
+ goto err;
+ }
+
+ msg.flags = I2C_M_RD;
+ msg.len = data->val_len;
+ ret = i2c_transfer(adapter, &msg, 1);
+ if (ret < 0) {
+ mutex_unlock(&cmd_mutex);
+ goto err;
+ }
+
+ if (data->val_len == I2C_8BIT)
+ data->val = val[0];
+ else if (data->val_len == I2C_16BIT)
+ data->val = (val[0] << 8) + val[1];
+ else if (data->val_len == I2C_32BIT)
+ data->val = (val[3] << 24) + (val[2] << 16) + (val[1] << 8) + val[0];
+ //pr_info("twsi_read_i2c: val[0]=0x%x,val[1]=0x%x,val[2]=0x%x,val[3]=0x%x\n",val[0],val[1],val[2],val[3]);
+ mutex_unlock(&cmd_mutex);
+
+ return 0;
+
+err:
+ pr_info("Failed reading register 0x%02x!", data->reg);
+ return ret;
+}
+
+static void TWSI_Init(I2C_FAST_MODE mode, unsigned int i2c_no)
+{
+ dptc_i2c_data.twsi_no = i2c_no;
+ dptc_i2c_data.addr = 0x6c;
+ dptc_i2c_data.reg_len = 1;//I2C_8BIT;
+ dptc_i2c_data.val_len = 4;//I2C_32BIT;
+}
+
+static int TWSI_REG_WRITE_DPTC(uint8_t i2c_no, uint8_t slaveaddress, uint8_t addr, uint32_t data)
+{
+ int ret=0;
+
+ dptc_i2c_data.twsi_no = i2c_no;
+ dptc_i2c_data.addr = slaveaddress;
+ dptc_i2c_data.reg = addr;
+ dptc_i2c_data.val = data;
+ ret = twsi_write_i2c(&dptc_i2c_data);
+ if(0==ret)
+ return 1;
+ else
+ return -1;
+}
+
+static int TWSI_REG_READ_DPTC(uint8_t i2c_no, uint8_t slaveaddress, uint8_t addr)
+{
+ int ret=0;
+
+ dptc_i2c_data.twsi_no = i2c_no;
+ dptc_i2c_data.addr = slaveaddress;
+ dptc_i2c_data.reg = addr;
+ dptc_i2c_data.val = 0x00;
+ ret = twsi_read_i2c(&dptc_i2c_data);
+ if(0==ret)
+ return dptc_i2c_data.val;
+ else
+ return -1;
+}
+
+
+void dptc_top_write(uint32_t reg, uint32_t data)
+{
+ int ret = 0;
+ uint32_t rd_data;
+
+ ret = TWSI_REG_WRITE_DPTC(I2C_NO, TOP_SLAVE_ADDR, reg >> 2, data);
+ rd_data = TWSI_REG_READ_DPTC(I2C_NO, TOP_SLAVE_ADDR, reg >> 2);
+ if(rd_data != data)
+ pr_err("fb: %s failed, [0x%x] = 0x%x\n", __func__, reg, data);
+}
+
+uint32_t dptc_top_read(uint32_t reg)
+{
+ uint32_t data = 0;
+
+ data = TWSI_REG_READ_DPTC(I2C_NO, TOP_SLAVE_ADDR, reg >> 2);
+ pr_debug("fb: %s [0x%x] = 0x%x\n", __func__, reg, data);
+
+ return data;
+}
+
+void dptc_dsi_write(uint32_t reg, uint32_t data)
+{
+ int ret = 0;
+ uint32_t rd_data;
+
+ ret = TWSI_REG_WRITE_DPTC(I2C_NO, DSI_SLAVE_ADDR, reg >> 2, data);
+ rd_data = TWSI_REG_READ_DPTC(I2C_NO, DSI_SLAVE_ADDR, reg >> 2);
+ if(rd_data != data)
+ pr_err("fb: %s failed, [0x%x] = 0x%x\n", __func__, reg, data);
+}
+
+uint32_t dptc_dsi_read(uint32_t reg)
+{
+ uint32_t data = 0;
+
+ data = TWSI_REG_READ_DPTC(I2C_NO, DSI_SLAVE_ADDR, reg >> 2);
+
+ pr_debug("fb: %s [0x%x] = 0x%x\n", __func__, reg, data);
+ return data;
+}
+
+void dptc_board_init(void)
+{
+ uint32_t data;
+
+ TWSI_Init(STANDARD_MODE, I2C_NO);
+ msleep(100);
+
+ data = dptc_top_read(0x04); // enter function 4
+ data |= 0x4;
+ dptc_top_write(0x4, data);
+
+ data = dptc_top_read(0x8); // pll control
+ data |= 0x1;
+ dptc_top_write(0x8, data);
+
+ data = dptc_top_read(0x18); // clk reset
+ data |= 0x4;
+ dptc_top_write(0x18, data);
+
+ dptc_top_write(0x0c, 0x3e627627);// setting pll 1.62G // success
+ dptc_top_write(0x10, 0x428D4420);
+
+ data = dptc_top_read(0x14); // enable ck_dsi
+ data |= (0xff00); // ???
+ dptc_top_write(0x14, data);
+
+ data = dptc_top_read(0x08); // power up PLL
+ data |= 0x02;
+}
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _DPTC_DRV_H_
+#define _DPTC_DRV_H_
+
+
+#ifdef CONFIG_SPACEMIT_FPGA
+#define DPTC_DPHY_TEST 1
+#endif
+
+typedef enum
+{
+ STANDARD_MODE = 0, /*100Kbps*/
+ FAST_MODE = 1, /*400Kbps*/
+ HS_MODE = 2, /*3.4 Mbps slave/3.3 Mbps master,standard mode when not doing a high speed transfer*/
+ HS_MODE_FAST = 3, /*3.4 Mbps slave/3.3 Mbps master,fast mode when not doing a high speed transfer*/
+} I2C_FAST_MODE;
+
+struct twsi_data {
+ u8 twsi_no;
+ u8 reg_len;/* byte num*/
+ u8 val_len;/* byte num*/
+ u8 addr; /* 7 bit i2c address*/
+ u16 reg;
+ u32 val;
+};
+
+enum i2c_len {
+ I2C_8BIT = 1,
+ I2C_16BIT = 2,
+ I2C_24BIT = 3,
+ I2C_32BIT = 4,
+};
+
+void dptc_dsi_write(uint32_t reg, uint32_t data);
+uint32_t dptc_dsi_read(uint32_t reg);
+void dptc_board_init(void);
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/clk-provider.h>
+
+#include "spacemit_dsi_hw.h"
+#include "../spacemit_dphy.h"
+#include "../spacemit_dsi.h"
+
+#include "spacemit_dptc_drv.h"
+
+#define SPACEMIT_DSI_MAX_TX_FIFO_BYTES 256
+#define SPACEMIT_DSI_MAX_RX_FIFO_BYTES 64
+#define SPACEMIT_DSI_MAX_CMD_FIFO_BYTES 1024
+
+#define to_dsi_bcnt(timing, bpp) (((timing) * (bpp)) >> 3)
+
+static unsigned int spacemit_dsi_lane[5] = {0, 0x1, 0x3, 0x7, 0xf};
+
+static unsigned char dsi_bit(unsigned int index, unsigned char *pdata)
+{
+ unsigned char ret;
+ unsigned int cindex, bindex;
+ cindex = index / 8;
+ bindex = index % 8;
+
+ if (pdata[cindex] & (0x1 << bindex))
+ ret = (unsigned char) 0x1;
+ else
+ ret = (unsigned char) 0x0;
+
+ return ret;
+}
+
+static unsigned char calculate_ecc(unsigned char *pdata)
+{
+ unsigned char ret;
+ unsigned char p[8];
+
+ p[7] = (unsigned char) 0x0;
+ p[6] = (unsigned char) 0x0;
+
+ p[5] = (unsigned char) (
+ (
+ dsi_bit(10, pdata) ^
+ dsi_bit(11, pdata) ^
+ dsi_bit(12, pdata) ^
+ dsi_bit(13, pdata) ^
+ dsi_bit(14, pdata) ^
+ dsi_bit(15, pdata) ^
+ dsi_bit(16, pdata) ^
+ dsi_bit(17, pdata) ^
+ dsi_bit(18, pdata) ^
+ dsi_bit(19, pdata) ^
+ dsi_bit(21, pdata) ^
+ dsi_bit(22, pdata) ^
+ dsi_bit(23, pdata)
+ )
+ );
+ p[4] = (unsigned char) (
+ dsi_bit(4, pdata) ^
+ dsi_bit(5, pdata) ^
+ dsi_bit(6, pdata) ^
+ dsi_bit(7, pdata) ^
+ dsi_bit(8, pdata) ^
+ dsi_bit(9, pdata) ^
+ dsi_bit(16, pdata) ^
+ dsi_bit(17, pdata) ^
+ dsi_bit(18, pdata) ^
+ dsi_bit(19, pdata) ^
+ dsi_bit(20, pdata) ^
+ dsi_bit(22, pdata) ^
+ dsi_bit(23, pdata)
+ );
+ p[3] = (unsigned char) (
+ (
+ dsi_bit(1, pdata) ^
+ dsi_bit(2, pdata) ^
+ dsi_bit(3, pdata) ^
+ dsi_bit(7, pdata) ^
+ dsi_bit(8, pdata) ^
+ dsi_bit(9, pdata) ^
+ dsi_bit(13, pdata) ^
+ dsi_bit(14, pdata) ^
+ dsi_bit(15, pdata) ^
+ dsi_bit(19, pdata) ^
+ dsi_bit(20, pdata) ^
+ dsi_bit(21, pdata) ^
+ dsi_bit(23, pdata)
+ )
+ );
+ p[2] = (unsigned char) (
+ (
+ dsi_bit(0, pdata) ^
+ dsi_bit(2, pdata) ^
+ dsi_bit(3, pdata) ^
+ dsi_bit(5, pdata) ^
+ dsi_bit(6, pdata) ^
+ dsi_bit(9, pdata) ^
+ dsi_bit(11, pdata) ^
+ dsi_bit(12, pdata) ^
+ dsi_bit(15, pdata) ^
+ dsi_bit(18, pdata) ^
+ dsi_bit(20, pdata) ^
+ dsi_bit(21, pdata) ^
+ dsi_bit(22, pdata)
+ )
+ );
+ p[1] = (unsigned char) (
+ (
+ dsi_bit(0, pdata) ^
+ dsi_bit(1, pdata) ^
+ dsi_bit(3, pdata) ^
+ dsi_bit(4, pdata) ^
+ dsi_bit(6, pdata) ^
+ dsi_bit(8, pdata) ^
+ dsi_bit(10, pdata) ^
+ dsi_bit(12, pdata) ^
+ dsi_bit(14, pdata) ^
+ dsi_bit(17, pdata) ^
+ dsi_bit(20, pdata) ^
+ dsi_bit(21, pdata) ^
+ dsi_bit(22, pdata) ^
+ dsi_bit(23, pdata)
+ )
+ );
+ p[0] = (unsigned char) (
+ (
+ dsi_bit(0, pdata) ^
+ dsi_bit(1, pdata) ^
+ dsi_bit(2, pdata) ^
+ dsi_bit(4, pdata) ^
+ dsi_bit(5, pdata) ^
+ dsi_bit(7, pdata) ^
+ dsi_bit(10, pdata) ^
+ dsi_bit(11, pdata) ^
+ dsi_bit(13, pdata) ^
+ dsi_bit(16, pdata) ^
+ dsi_bit(20, pdata) ^
+ dsi_bit(21, pdata) ^
+ dsi_bit(22, pdata) ^
+ dsi_bit(23, pdata)
+ )
+ );
+ ret = (unsigned char)(
+ p[0] |
+ (p[1] << 0x1) |
+ (p[2] << 0x2) |
+ (p[3] << 0x3) |
+ (p[4] << 0x4) |
+ (p[5] << 0x5)
+ );
+ return ret;
+}
+
+static unsigned short gs_crc16_generation_code = 0x8408;
+static unsigned short calculate_crc16(unsigned char *pdata, unsigned
+ short count)
+{
+ unsigned short byte_counter;
+ unsigned char bit_counter;
+ unsigned char data;
+ unsigned short crc16_result = 0xFFFF;
+ if (count > 0) {
+ for (byte_counter = 0; byte_counter < count;
+ byte_counter++) {
+ data = *(pdata + byte_counter);
+ for (bit_counter = 0; bit_counter < 8; bit_counter++) {
+ if (((crc16_result & 0x0001) ^ ((0x0001 *
+ data) & 0x0001)) > 0)
+ crc16_result = ((crc16_result >> 1)
+ & 0x7FFF) ^ gs_crc16_generation_code;
+ else
+ crc16_result = (crc16_result >> 1)
+ & 0x7FFF;
+ data = (data >> 1) & 0x7F;
+ }
+ }
+ }
+ return crc16_result;
+}
+
+static void dsi_reset(void __iomem *base_addr)
+{
+ uint32_t reg;
+
+ reg = CFG_SOFT_RST | CFG_SOFT_RST_REG | CFG_CLR_PHY_FIFO | CFG_RST_TXLP |
+ CFG_RST_CPU | CFG_RST_CPN | CFG_RST_VPN | CFG_DSI_PHY_RST;
+
+ /* software reset DSI module */
+ dsi_write(base_addr, DSI_CTRL_0, reg);
+ /* Note: there need some delay after set CFG_SOFT_RST */
+ udelay(1000);
+ dsi_write(base_addr, DSI_CTRL_0, 0);
+
+ dsi_write(base_addr, DSI_IRQ_ST, 0xFFFFFFFF);
+}
+
+static void dsi_enable_video_mode(void __iomem *base_addr, bool enable)
+{
+ if(enable)
+ dsi_set_bits(base_addr, DSI_CTRL_0, CFG_VPN_TX_EN | CFG_VPN_SLV | CFG_VPN_EN);
+ else
+ dsi_clear_bits(base_addr, DSI_CTRL_0, CFG_VPN_TX_EN | CFG_VPN_EN);
+}
+
+static void dsi_enable_cmd_mode(void __iomem *base_addr, bool enable)
+{
+ if(enable)
+ dsi_set_bits(base_addr, DSI_CTRL_0, CFG_CPN_EN);
+ else
+ dsi_clear_bits(base_addr, DSI_CTRL_0, CFG_CPN_EN);
+}
+
+static void dsi_enable_eotp(void __iomem *base_addr, bool enable)
+{
+ if(enable)
+ dsi_set_bits(base_addr, DSI_CTRL_1, CFG_EOTP_EN);
+ else
+ dsi_clear_bits(base_addr, DSI_CTRL_1, CFG_EOTP_EN);
+}
+
+static void dsi_enable_lptx_lanes(void __iomem *base_addr, uint32_t lane_num)
+{
+ dsi_write_bits(base_addr, DSI_CPU_CMD_1,
+ CFG_TXLP_LPDT_MASK, lane_num << CFG_TXLP_LPDT_SHIFT);
+}
+
+static void dsi_enable_split_mode(void __iomem *base_addr, bool splite_mode)
+{
+ if(splite_mode){
+ dsi_set_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_SPLIT_EN);
+ } else {
+ dsi_clear_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_SPLIT_EN);
+ }
+}
+
+static void dsi_enable_irq(void __iomem *base_addr, bool enable)
+{
+ if (enable)
+ dsi_set_bits(base_addr, DSI_IRQ_MASK, DSI_IRQ_MASK_BITS);
+ else
+ dsi_clear_bits(base_addr, DSI_IRQ_MASK, DSI_IRQ_MASK_BITS);
+}
+
+static int dsi_write_cmd(void __iomem *base_addr, uint8_t *parameter, uint8_t count, bool lp)
+{
+ uint32_t send_data = 0, reg, timeout, tmp, i;
+ bool turnaround;
+ uint32_t len;
+
+ if(lp)
+ pr_debug("%s: %d packet data will be write in lp mode \n", __func__, count);
+ else
+ pr_debug("%s: %d data will be write in hs mode\n", __func__, count);
+
+ /* write all packet bytes to packet data buffer */
+ for (i = 0; i < count; i++) {
+ send_data |= parameter[i] << ((i % 4) * 8);
+ if (0 ==((i + 1) % 4)) {
+ dsi_write(base_addr, DSI_CPU_WDAT, send_data);
+ reg = CFG_CPU_DAT_REQ | CFG_CPU_DAT_RW |((i - 3) << CFG_CPU_DAT_ADDR_SHIFT);
+ dsi_write(base_addr, DSI_CPU_CMD_3, reg);
+ /* wait write operation done */
+ timeout = 1000;
+ do {
+ timeout--;
+ tmp = dsi_read(base_addr, DSI_CPU_CMD_3);
+ } while ((tmp & CFG_CPU_DAT_REQ) && timeout);
+ if (timeout == 0)
+ pr_err("DSI write data to the packet data buffer not done.\n");
+ send_data = 0;
+ }
+ }
+
+ /* handle last none 4Byte align data */
+ if (0 != i % 4) {
+ dsi_write(base_addr, DSI_CPU_WDAT, send_data);
+ reg = CFG_CPU_DAT_REQ | CFG_CPU_DAT_RW |((4 * (i / 4)) << CFG_CPU_DAT_ADDR_SHIFT);
+ dsi_write(base_addr, DSI_CPU_CMD_3, reg);
+ /* wait write operation done */
+ timeout = 1000;
+ do {
+ timeout--;
+ tmp = dsi_read(base_addr, DSI_CPU_CMD_3);
+ } while ((tmp & CFG_CPU_DAT_REQ) && timeout);
+ if (timeout == 0)
+ pr_err("DSI write data to the packet data buffer not done.\n");
+ send_data = 0;
+ }
+
+ if (parameter[0] == SPACEMIT_DSI_DCS_READ ||
+ parameter[0] == SPACEMIT_DSI_GENERIC_READ1)
+ turnaround = true;
+ else
+ turnaround = false;
+
+ len = count;
+#if 0
+ /* The packet length should contain CRC_bytes_length in Aquilac_DSI version */
+ if ((parameter[0] == SPACEMIT_DSI_DCS_LWRITE ||
+ parameter[0] == SPACEMIT_DSI_GENERIC_LWRITE) && !lp)
+ len = count - 6;
+#endif
+ reg = CFG_CPU_CMD_REQ |
+ ((count == 4) ? CFG_CPU_SP : 0) |
+ (turnaround ? CFG_CPU_TURN : 0) |
+ (lp ? CFG_CPU_TXLP : 0) |
+ (len << CFG_CPU_WC_SHIFT);
+
+ /* send out the packet */
+ dsi_write(base_addr, DSI_CPU_CMD_0, reg);
+ /* wait packet be sent out */
+ timeout = 1000;
+ do {
+ timeout--;
+ tmp = dsi_read(base_addr, DSI_CPU_CMD_0);
+ udelay(50);
+ } while ((tmp & CFG_CPU_CMD_REQ) && timeout);
+ if (0 == timeout) {
+ pr_info("%s: DSI send out packet maybe failed.\n", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void dsi_config_video_mode(struct spacemit_dsi_device *dsi_ctx, struct spacemit_mipi_info *mipi_info)
+{
+ uint32_t hsync_b, hbp_b, hact_b, hex_b, hfp_b, httl_b;
+ uint32_t hsync, hbp, hact, httl, v_total;
+ uint32_t hsa_wc, hbp_wc, hact_wc, hex_wc, hfp_wc, hlp_wc;
+ uint32_t bpp, hss_bcnt = 4, hse_bct = 4, lgp_over_head = 6, reg;
+ uint32_t slot_cnt0, slot_cnt1;
+ uint32_t dsi_ex_pixel_cnt = 0;
+ uint32_t dsi_hex_en = 0;
+ uint32_t width, lane_number;
+ void __iomem *base_addr = dsi_ctx->base_addr;
+ struct spacemit_dsi_advanced_setting *adv_setting = &dsi_ctx->adv_setting;
+
+ switch(mipi_info->rgb_mode){
+ case DSI_INPUT_DATA_RGB_MODE_565:
+ bpp = 16;
+ break;
+ case DSI_INPUT_DATA_RGB_MODE_666PACKET:
+ bpp = 18;
+ break;
+ case DSI_INPUT_DATA_RGB_MODE_666UNPACKET:
+ bpp = 18;
+ break;
+ case DSI_INPUT_DATA_RGB_MODE_888:
+ bpp = 24;
+ break;
+ default:
+ bpp = 24;
+ }
+
+ v_total = mipi_info->height + mipi_info->vfp + mipi_info->vbp + mipi_info->vsync;
+
+ if(mipi_info->split_enable) {
+ if(( 0 != (mipi_info->width & 0x1)) || (0 != (mipi_info->lane_number & 0x1))){
+ pr_err("%s: warning:Invalid split config(lane = %d, width = %d)\n",
+ __func__, mipi_info->lane_number, mipi_info->width);
+ }
+ width = mipi_info->width >> 1;
+ lane_number = mipi_info->lane_number >> 1;
+ } else {
+ width = mipi_info->width;
+ lane_number = mipi_info->lane_number;
+ }
+
+ hact_b = to_dsi_bcnt(width, bpp);
+ hfp_b = to_dsi_bcnt(mipi_info->hfp, bpp);
+ hbp_b = to_dsi_bcnt(mipi_info->hbp, bpp);
+ hsync_b = to_dsi_bcnt(mipi_info->hsync, bpp);
+ hex_b = to_dsi_bcnt(dsi_ex_pixel_cnt, bpp);
+ httl_b = hact_b + hsync_b + hfp_b + hbp_b + hex_b;
+ slot_cnt0 = (httl_b - hact_b) / lane_number + 3;
+ slot_cnt1 = slot_cnt0;
+
+ hact = hact_b / lane_number;
+ hbp = hbp_b / lane_number;
+ hsync = hsync_b / lane_number;
+ httl = (hact_b + hfp_b + hbp_b + hsync_b) / lane_number;
+
+ /* word count in the unit of byte */
+ hsa_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+ (hsync_b - hss_bcnt - lgp_over_head) : 0;
+
+ /* Hse is with backporch */
+ hbp_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+ (hbp_b - hse_bct - lgp_over_head)
+ : (hsync_b + hbp_b - hss_bcnt - lgp_over_head);
+
+ hfp_wc = ((mipi_info->burst_mode == DSI_BURST_MODE_BURST) && (dsi_hex_en == 0)) ?
+ (hfp_b + hex_b - lgp_over_head - lgp_over_head) :
+ (hfp_b - lgp_over_head - lgp_over_head);
+
+ hact_wc = (width * bpp) >> 3;
+
+ /* disable Hex currently */
+ hex_wc = 0;
+
+ /* There is no hlp with active data segment. */
+ hlp_wc = (mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE) ?
+ (httl_b - hsync_b - hse_bct - lgp_over_head) :
+ (httl_b - hss_bcnt - lgp_over_head);
+
+ /* FIXME - need to double check the (*3) is bytes_per_pixel
+ * from input data or output to panel
+ */
+
+ /*Jessica: need be calculated by really case*/
+ dsi_write(base_addr, DSI_VPN_CTRL_0, (0x50<<16) | 0xc08);
+
+ /* SET UP LCD1 TIMING REGISTERS FOR DSI BUS */
+ dsi_write(base_addr, DSI_VPN_TIMING_0, (hact << 16) | httl);
+ dsi_write(base_addr, DSI_VPN_TIMING_1, (hsync << 16) | hbp);
+ dsi_write(base_addr, DSI_VPN_TIMING_2, ((mipi_info->height)<<16) | (v_total));
+ dsi_write(base_addr, DSI_VPN_TIMING_3, ((mipi_info->vsync) << 16) | (mipi_info->vbp));
+
+ /* SET UP LCD1 WORD COUNT REGISTERS FOR DSI BUS */
+ dsi_write(base_addr, DSI_VPN_WC_0, (hbp_wc << 16) | hsa_wc);
+ dsi_write(base_addr, DSI_VPN_WC_1, (hfp_wc << 16) | hact_wc);
+ dsi_write(base_addr, DSI_VPN_WC_2, (hex_wc << 16) | hlp_wc);
+
+ dsi_write(base_addr, DSI_VPN_SLOT_CNT_0, (slot_cnt0 << 16) | slot_cnt0);
+ dsi_write(base_addr, DSI_VPN_SLOT_CNT_1, (slot_cnt1 << 16) | slot_cnt1);
+
+ /* Configure LCD control register 1 FOR DSI BUS */
+#ifdef DPTC_DPHY_TEST
+ adv_setting->hact_wc_en = 0;
+ adv_setting->timing_check_dis = 1;
+ adv_setting->auto_dly_dis = 1;
+#endif
+
+ reg = adv_setting->vsync_rst_en << CFG_VPN_VSYNC_RST_EN_SHIFT |
+ adv_setting->auto_wc_dis << CFG_VPN_AUTO_WC_DIS_SHIFT |
+ adv_setting->hact_wc_en << CFG_VPN_HACT_WC_EN_SHIFT |
+ adv_setting->timing_check_dis << CFG_VPN_TIMING_CHECK_DIS_SHIFT |
+ adv_setting->auto_dly_dis << CFG_VPN_AUTO_DLY_DIS_SHIFT |
+ adv_setting->hlp_pkt_en << CFG_VPN_HLP_PKT_EN_SHIFT |
+ adv_setting->hex_pkt_en << CFG_VPN_HEX_PKT_EN_SHIFT |
+ adv_setting->hfp_pkt_en << CFG_VPN_HFP_PKT_EN_SHIFT |
+ adv_setting->hbp_pkt_en << CFG_VPN_HBP_PKT_EN_SHIFT |
+ adv_setting->hse_pkt_en << CFG_VPN_HSE_PKT_EN_SHIFT |
+ adv_setting->hsa_pkt_en << CFG_VPN_HSA_PKT_EN_SHIFT |
+ adv_setting->hex_slot_en<< CFG_VPN_HEX_SLOT_EN_SHIFT |
+ adv_setting->last_line_turn << CFG_VPN_LAST_LINE_TURN_SHIFT |
+ adv_setting->lpm_frame_en << CFG_VPN_LPM_FRAME_EN_SHIFT |
+ mipi_info->burst_mode << CFG_VPN_BURST_MODE_SHIFT |
+ mipi_info->rgb_mode << CFG_VPN_RGB_TYPE_SHIFT;
+ dsi_write(base_addr, DSI_VPN_CTRL_1,reg);
+
+ dsi_write_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_VPN_FIFO_AFULL_CNT_MASK,
+ 0 << CFG_VPN_FIFO_AFULL_CNT_SHIT);
+//#ifdef CONFIG_ESD_SUPPORT
+ dsi_set_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_VPN_FIFO_AFULL_BYPASS);
+//#else
+ //dsi_clear_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_VPN_FIFO_AFULL_BYPASS);
+//#endif
+ dsi_set_bits(base_addr, DSI_LCD_BDG_CTRL0, CFG_PIXEL_SWAP);
+
+ dsi_enable_cmd_mode(base_addr, false);
+ dsi_enable_video_mode(base_addr, true);
+}
+
+static void dsi_config_cmd_mode(struct spacemit_dsi_device *dsi_ctx, struct spacemit_mipi_info *mipi_info)
+{
+ int reg;
+ int rgb_mode, bpp;
+
+ switch(mipi_info -> rgb_mode){
+ case DSI_INPUT_DATA_RGB_MODE_565:
+ bpp = 16;
+ rgb_mode = 2;
+ break;
+ case DSI_INPUT_DATA_RGB_MODE_666UNPACKET:
+ bpp = 18;
+ rgb_mode = 1;
+ break;
+ case DSI_INPUT_DATA_RGB_MODE_888:
+ bpp = 24;
+ rgb_mode = 0;
+ break;
+ default:
+ pr_err("%s: unsupported rgb format!\n", __func__);
+ bpp = 24;
+ rgb_mode = 0;
+ }
+
+ reg = mipi_info->te_enable << CFG_CPN_TE_EN_SHIFT |
+ rgb_mode << CFG_CPN_RGB_TYPE_SHIFT |
+ 1 << CFG_CPN_BURST_MODE_SHIFT |
+ 0 << CFG_CPN_DMA_DIS_SHIFT |
+ 0 << CFG_CPN_ADDR0_EN_SHIFT;
+ dsi_write(dsi_ctx->base_addr, DSI_CPN_CMD, reg);
+
+ reg = mipi_info->width * bpp / 8 << CFG_CPN_PKT_CNT_SHIFT |
+ SPACEMIT_DSI_MAX_CMD_FIFO_BYTES << CFG_CPN_FIFO_FULL_LEVEL_SHIFT;
+ dsi_write(dsi_ctx->base_addr, DSI_CPN_CTRL_1,reg);
+
+ dsi_write_bits(dsi_ctx->base_addr, DSI_LCD_BDG_CTRL0, CFG_CPN_TE_EDGE_MASK,
+ mipi_info->te_pol << CFG_CPN_TE_EDGE_SHIFT);
+ dsi_write_bits(dsi_ctx->base_addr, DSI_LCD_BDG_CTRL0, CFG_CPN_VSYNC_EDGE_MASK,
+ mipi_info->vsync_pol << CFG_CPN_VSYNC_EDGE_SHIFT);
+ dsi_write_bits(dsi_ctx->base_addr, DSI_LCD_BDG_CTRL0, CFG_CPN_TE_MODE_MASK,
+ mipi_info->te_mode << CFG_CPN_TE_MODE_SHIFT);
+
+ reg = 0x80 << CFG_CPN_TE_DLY_CNT_SHIFT |
+ 0 << CFG_CPN_TE_LINE_CNT_SHIFT;
+ dsi_write(dsi_ctx->base_addr, DSI_LCD_BDG_CTRL1, reg);
+
+ dsi_enable_video_mode(dsi_ctx->base_addr, false);
+ dsi_enable_cmd_mode(dsi_ctx->base_addr, true);
+}
+
+static int dsi_write_cmd_array(struct spacemit_dsi_device *dsi_ctx,
+ struct spacemit_dsi_cmd_desc *cmds,int count)
+{
+ struct spacemit_dsi_cmd_desc cmd_line;
+ uint8_t type, parameter[SPACEMIT_DSI_MAX_TX_FIFO_BYTES], len;
+ uint32_t crc, loop;
+ int ret = 0;
+
+ pr_debug("%s: %d cmd will be write\n", __func__, count);
+
+ if(NULL == dsi_ctx) {
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ for (loop = 0; loop < count; loop++) {
+ cmd_line = cmds[loop];
+ type = cmd_line.cmd_type;
+ len = cmd_line.length;
+ memset(parameter, 0x00, len + 6);
+ parameter[0] = type & 0xff;
+ switch (type) {
+ case SPACEMIT_DSI_DCS_SWRITE:
+ case SPACEMIT_DSI_DCS_SWRITE1:
+ case SPACEMIT_DSI_DCS_READ:
+ case SPACEMIT_DSI_GENERIC_READ1:
+ case SPACEMIT_DSI_SET_MAX_PKT_SIZE:
+ memcpy(¶meter[1], cmd_line.data, len);
+ len = 4;
+ break;
+ case SPACEMIT_DSI_GENERIC_LWRITE:
+ case SPACEMIT_DSI_DCS_LWRITE:
+ parameter[1] = len & 0xff;
+ parameter[2] = 0;
+ memcpy(¶meter[4], cmd_line.data, len);
+ crc = calculate_crc16(¶meter[4], len);
+ parameter[len + 4] = crc & 0xff;
+ parameter[len + 5] = (crc >> 8) & 0xff;
+ len += 6;
+ break;
+ default:
+ pr_err("%s: data type not supported 0x%8x\n",__func__, type);
+ break;
+ }
+
+ parameter[3] = calculate_ecc(parameter);
+
+ /* send dsi commands */
+ ret = dsi_write_cmd(dsi_ctx->base_addr, parameter, len, cmd_line.lp);
+ if(ret)
+ return -1;
+
+ // if (0 != cmd_line.delay)
+ // msleep(cmd_line.delay);
+ }
+ return 0;
+}
+
+static int dsi_read_cmd_array(struct spacemit_dsi_device *dsi_ctx, struct spacemit_dsi_rx_buf *dbuf,
+ struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+ uint8_t parameter[SPACEMIT_DSI_MAX_RX_FIFO_BYTES];
+ uint32_t i, rx_reg, timeout, tmp, packet,
+ data_pointer, byte_count;
+
+ pr_debug("%s: %d cmds will be write\n", __func__, count);
+
+ if(NULL == dsi_ctx) {
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ memset(dbuf, 0x0, sizeof(struct spacemit_dsi_rx_buf));
+ dsi_write_cmd_array(dsi_ctx, cmds, count);
+
+ timeout = 1000;
+ do {
+ timeout--;
+ tmp = dsi_read(dsi_ctx->base_addr, DSI_IRQ_ST);
+ } while (((tmp & IRQ_RX_PKT) == 0) && timeout);
+ if (0 == timeout) {
+ pr_err("%s: dsi didn't receive packet, irq status 0x%x\n", __func__, tmp);
+ return -1;
+ }
+
+ if (tmp & IRQ_RX_TRG3)
+ pr_err("%s: not defined package is received\n", __func__);
+ if (tmp & IRQ_RX_TRG2)
+ pr_err("%s: ACK package is received\n", __func__);
+ if (tmp & IRQ_RX_TRG1)
+ pr_err("%s: TE trigger is received\n", __func__);
+ if (tmp & IRQ_RX_ERR) {
+ tmp = dsi_read(dsi_ctx->base_addr, DSI_RX_PKT_HDR_0);
+ pr_err("%s: error: ACK with error report (0x%x)\n", __func__, tmp);
+ }
+
+ packet = dsi_read(dsi_ctx->base_addr, DSI_RX_PKT_ST_0);
+
+ data_pointer = (packet & CFG_RX_PKT0_PTR_MASK) >> CFG_RX_PKT0_PTR_SHIFT;
+ tmp = dsi_read(dsi_ctx->base_addr, DSI_RX_PKT_CTRL_1);
+ byte_count = tmp & CFG_RX_PKT_BCNT_MASK;
+
+ memset(parameter, 0x00, byte_count);
+ for (i = data_pointer; i < data_pointer + byte_count; i++) {
+ rx_reg = dsi_read(dsi_ctx->base_addr, DSI_RX_PKT_CTRL);
+ rx_reg &= ~CFG_RX_PKT_RD_PTR_MASK;
+ rx_reg |= CFG_RX_PKT_RD_REQ | (i << CFG_RX_PKT_RD_PTR_SHIFT);
+ dsi_write(dsi_ctx->base_addr, DSI_RX_PKT_CTRL, rx_reg);
+ count = 10000;
+ do {
+ count--;
+ rx_reg = dsi_read(dsi_ctx->base_addr, DSI_RX_PKT_CTRL);
+ } while (rx_reg & CFG_RX_PKT_RD_REQ && count);
+ if ( 0 == count)
+ pr_err("%s: error: read Rx packet FIFO error\n", __func__);
+ parameter[i - data_pointer] = rx_reg & 0xff;
+ }
+ switch (parameter[0]) {
+ case SPACEMIT_DSI_ACK_ERR_RESP:
+ pr_err("%s: error: Acknowledge with error report\n", __func__);
+ break;
+ case SPACEMIT_DSI_EOTP:
+ pr_err("%s: error: End of Transmission packet\n", __func__);
+ break;
+ case SPACEMIT_DSI_GEN_READ1_RESP:
+ case SPACEMIT_DSI_DCS_READ1_RESP:
+ dbuf->data_type = parameter[0];
+ dbuf->length = 1;
+ memcpy(dbuf->data, ¶meter[1], dbuf->length);
+ break;
+ case SPACEMIT_DSI_GEN_READ2_RESP:
+ case SPACEMIT_DSI_DCS_READ2_RESP:
+ dbuf->data_type = parameter[0];
+ dbuf->length = 2;
+ memcpy(dbuf->data, ¶meter[1], dbuf->length);
+ break;
+ case SPACEMIT_DSI_GEN_LREAD_RESP:
+ case SPACEMIT_DSI_DCS_LREAD_RESP:
+ dbuf->data_type = parameter[0];
+ dbuf->length = (parameter[2] << 8) | parameter[1];
+ memcpy(dbuf->data, ¶meter[4], dbuf->length);
+ pr_debug("%s: read %d data: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", __func__, dbuf->length,
+ parameter[4], parameter[5], parameter[6], parameter[7], parameter[8]);
+ break;
+ }
+ return 0;
+}
+
+static void dsi_open_dphy(struct spacemit_dsi_device* device_ctx, bool ready)
+{
+ struct spacemit_dphy *spacemit_dphy = device_ctx->phy;
+ struct spacemit_dphy_ctx *dphy_config = &spacemit_dphy->ctx;
+ struct spacemit_mipi_info *mipi_info = &device_ctx->mipi_info;
+
+ dphy_config->base_addr = device_ctx->base_addr;
+ //dphy_config->phy_freq = device_ctx->bit_clk_rate / 1000;
+ //dphy_config->esc_clk = device_ctx->esc_clk_rate / 1000;
+ dphy_config->phy_freq = mipi_info->phy_bit_clock / 1000;
+ dphy_config->esc_clk = mipi_info->phy_esc_clock / 1000;
+
+ if(mipi_info->split_enable)
+ dphy_config->lane_num = mipi_info->lane_number >> 1;
+ else
+ dphy_config->lane_num = mipi_info->lane_number;
+ dphy_config->status = DPHY_STATUS_UNINIT;
+
+ if(ready){
+ dphy_config->status = DPHY_STATUS_INIT;
+ return;
+ }
+
+ spacemit_dphy_resume(spacemit_dphy);
+}
+
+static void dsi_close_dphy(struct spacemit_dphy* spacemit_dphy)
+{
+ spacemit_dphy_suspend(spacemit_dphy);
+}
+
+static void dsi_ready_dphy(struct spacemit_dsi_device* device_ctx)
+{
+}
+
+int spacemit_dsi_open(struct spacemit_dsi_device* device_ctx, bool ready)
+{
+ int lane_number;
+ struct spacemit_mipi_info *mipi_info = &device_ctx->mipi_info;
+
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ if((NULL == device_ctx) || (NULL == mipi_info)){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+#ifdef DPTC_DPHY_TEST
+ if(!ready) {
+ dptc_board_init();
+ }
+#endif
+
+ pr_debug("%s: dsi(%d) Enter, ready = %d\n", __func__, device_ctx->id, ready);
+
+ if(mipi_info->split_enable)
+ lane_number = mipi_info->lane_number >> 1;
+ else
+ lane_number = mipi_info->lane_number;
+
+ if(!ready)
+ dsi_reset(device_ctx->base_addr);
+
+ dsi_open_dphy(device_ctx, ready);
+ if(!ready) {
+ dsi_enable_split_mode(device_ctx->base_addr, mipi_info->split_enable);
+ dsi_enable_lptx_lanes(device_ctx->base_addr, spacemit_dsi_lane[lane_number]);
+ dsi_enable_eotp(device_ctx->base_addr, mipi_info->eotp_enable);
+ }
+
+ dsi_enable_irq(device_ctx->base_addr, true);
+
+ device_ctx->status = DSI_STATUS_OPENED;
+ return 0;
+}
+
+int spacemit_dsi_close(struct spacemit_dsi_device* device_ctx)
+{
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ if(NULL == device_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ pr_debug("%s: dsi(%d) Enter\n", __func__, device_ctx->id);
+
+ dsi_enable_irq(device_ctx->base_addr, false);
+
+ dsi_close_dphy(device_ctx->phy);
+
+ device_ctx->status = DSI_STATUS_UNINIT;
+
+ pr_debug("%s: dsi(%d) leave\n", __func__, device_ctx->id);
+ return 0;
+}
+
+int spacemit_dsi_ready_for_datatx(struct spacemit_dsi_device* device_ctx)
+{
+ struct spacemit_mipi_info *mipi_info = &device_ctx->mipi_info;
+
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ if((NULL == device_ctx) || (NULL == mipi_info)){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ pr_debug("%s: dsi(%d) Enter\n", __func__, device_ctx->id);
+
+ if(mipi_info->work_mode == SPACEMIT_DSI_MODE_CMD){
+ dsi_config_cmd_mode(device_ctx, mipi_info);
+ } else {
+ dsi_config_video_mode(device_ctx, mipi_info);
+ }
+
+ dsi_ready_dphy(device_ctx);
+ return 0;
+}
+
+int spacemit_dsi_close_datatx(struct spacemit_dsi_device* device_ctx)
+{
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ if(NULL == device_ctx){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ pr_debug("%s: dsi(%d) Enter\n", __func__, device_ctx->id);
+
+ dsi_enable_cmd_mode(device_ctx->base_addr, false);
+ dsi_enable_video_mode(device_ctx->base_addr, false);
+
+ return 0;
+}
+
+int spacemit_dsi_write_cmds(struct spacemit_dsi_device* device_ctx,
+ struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ if((NULL == device_ctx) || (NULL == cmds)){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ pr_debug("%s: dsi(%d) Enter\n", __func__, device_ctx->id);
+
+ return dsi_write_cmd_array(device_ctx, cmds, count);
+}
+
+int spacemit_dsi_read_cmds(struct spacemit_dsi_device* device_ctx, struct spacemit_dsi_rx_buf *dbuf,
+ struct spacemit_dsi_cmd_desc *cmds, int count)
+{
+#ifdef LCD_IS_READY
+ return 0;
+#endif
+
+ if((NULL == device_ctx) || (NULL == cmds)){
+ pr_err("%s: Invalid param\n", __func__);
+ return -1;
+ }
+
+ pr_debug("%s: dsi(%d) Enter\n", __func__, device_ctx->id);
+ return dsi_read_cmd_array(device_ctx, dbuf, cmds, count);
+}
+
+int spacemit_dsi_parse_dt(struct spacemit_dsi_device* device_ctx, struct device_node *np)
+{
+ return 0;
+}
+
+int spacemit_dsi_isr(struct spacemit_dsi_device* device_ctx)
+{
+ uint32_t irq_st;
+
+ irq_st = dsi_read(device_ctx->base_addr, DSI_IRQ_ST);
+
+ /*clear interrupt*/
+ dsi_write(device_ctx->base_addr, DSI_IRQ_ST, irq_st);
+
+ // if (irq_st & DSI_IRQ_PHY_FIFO_UNDERRUN)
+ // pr_err("DSI: DSI_IRQ_PHY_FIFO_UNDERRUN %d\n", a);
+
+ if (irq_st & DSI_IRQ_VPN_BF_UNDERRUN_ERR)
+ pr_err("DSI: DSI_IRQ_VPN_BF_UNDERRUN_ERR\n");
+
+ if (irq_st & DSI_IRQ_VPN_BF_OVERRUN_ERR)
+ pr_err("DSI: DSI_IRQ_VPN_BF_OVERRUN_ERR\n");
+
+ return 0;
+}
+
+static struct dsi_core_ops dsi_core_ops = {
+ .parse_dt = spacemit_dsi_parse_dt,
+ .isr = spacemit_dsi_isr,
+ .dsi_open = spacemit_dsi_open,
+ .dsi_close = spacemit_dsi_close,
+ .dsi_write_cmds = spacemit_dsi_write_cmds,
+ .dsi_read_cmds = spacemit_dsi_read_cmds,
+ .dsi_ready_for_datatx = spacemit_dsi_ready_for_datatx,
+ .dsi_close_datatx = spacemit_dsi_close_datatx,
+};
+
+static struct ops_entry entry = {
+ .ver = "synopsys-dhost",
+ .ops = &dsi_core_ops,
+};
+
+static int __init dsi_core_register(void)
+{
+ return dsi_core_ops_register(&entry);
+}
+
+subsys_initcall(dsi_core_register);
+
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DSI_HW_H_
+#define _SPACEMIT_DSI_HW_H_
+
+#include <linux/io.h>
+#include <drm/drm_print.h>
+
+#define DSI_CTRL_0 0x0
+#define DSI_CTRL_1 0x4
+#define DSI_IRQ_ST1 0x8
+#define DSI_IRQ_MASK1 0xC
+#define DSI_IRQ_ST 0x10
+#define DSI_IRQ_MASK 0x14
+#define DSI_IRQ_PHY_FIFO_UNDERRUN BIT(23)
+#define DSI_IRQ_VPN_BF_UNDERRUN_ERR BIT(19)
+#define DSI_IRQ_VPN_BF_OVERRUN_ERR BIT(17)
+#define DSI_IRQ_MASK_BITS ( DSI_IRQ_PHY_FIFO_UNDERRUN | \
+ DSI_IRQ_VPN_BF_UNDERRUN_ERR | \
+ DSI_IRQ_VPN_BF_OVERRUN_ERR )
+
+#ifdef CONFIG_SPACEMIT_FPGA
+#define DSI_FPGA_PHY_CTRL_0 0x18
+#define DSI_FPGA_PHY_CTRL_1 0x1C
+#endif
+
+#define DSI_CPU_CMD_0 0x20
+#define DSI_CPU_CMD_1 0x24
+#define DSI_CPU_CMD_3 0x2C
+#define DSI_CPU_WDAT 0x30
+#define DSI_CPU_STATUS_0 0x34
+#define DSI_CPU_STATUS_1 0x38
+#define DSI_CPU_STATUS_2 0x3C
+#define DSI_CPU_STATUS_3 0x40
+#define DSI_CPU_STATUS_4 0x44
+
+#define DSI_CPN_STATUS_1 0x4C
+#define DSI_CPN_CMD 0x50
+#define DSI_CPN_CTRL_0 0x54
+#define DSI_CPN_CTRL_1 0x58
+#define DSI_CPN_STATUS_0 0x5C
+
+#define DSI_RX_PKT_ST_0 0x60
+#define DSI_RX_PKT_HDR_0 0x64
+#define DSI_RX_PKT_ST_1 0x68
+#define DSI_RX_PKT_HDR_1 0x6C
+#define DSI_RX_PKT_CTRL 0x70
+#define DSI_RX_PKT_CTRL_1 0x74
+#define DSI_RX_PKT_ST_2 0x78
+#define DSI_RX_PKT_HDR_2 0x7C
+
+#define DSI_LCD_BDG_CTRL0 0x84
+#define DSI_LCD_BDG_CTRL1 0x88
+
+#define DSI_TX_TIMER 0xE4
+#define DSI_RX_TIMER 0xE8
+#define DSI_TURN_TIMER 0xEC
+
+#define DSI_VPN_CTRL_0 0x100
+#define DSI_VPN_CTRL_1 0x104
+#define DSI_VPN_TIMING_0 0x110
+#define DSI_VPN_TIMING_1 0x114
+#define DSI_VPN_TIMING_2 0x118
+#define DSI_VPN_TIMING_3 0x11C
+#define DSI_VPN_WC_0 0x120
+#define DSI_VPN_WC_1 0x124
+#define DSI_VPN_WC_2 0x128
+#define DSI_VPN_SLOT_CNT_0 0x130
+#define DSI_VPN_SLOT_CNT_1 0x134
+#define DSI_VPN_SYNC_CODE 0x138
+#define DSI_VPN_STATUS_0 0x140
+#define DSI_VPN_STATUS_1 0x144
+#define DSI_VPN_STATUS_2 0x148
+#define DSI_VPN_STATUS_3 0x14C
+#define DSI_VPN_STATUS_4 0x150
+
+#define DSI_PHY_CTRL_0 0x180
+#define DSI_PHY_CTRL_1 0x184
+#define DSI_PHY_CTRL_2 0x188
+#define DSI_PHY_CTRL_3 0x18C
+#define DSI_PHY_STATUS_0 0x190
+#define DSI_PHY_STATUS_1 0x194
+#define DSI_PHY_LPRX_0 0x198
+#define DSI_PHY_LPRX_1 0x19C
+#define DSI_PHY_LPTX_0 0x1A0
+#define DSI_PHY_LPTX_1 0x1A4
+#define DSI_PHY_LPTX_2 0x1A8
+#define DSI_PHY_STATUS_2 0x1AC
+#define DSI_PHY_TIME_0 0x1C0
+#define DSI_PHY_TIME_1 0x1C4
+#define DSI_PHY_TIME_2 0x1C8
+#define DSI_PHY_TIME_3 0x1CC
+#define DSI_PHY_CODE_0 0x1D0
+#define DSI_PHY_CODE_1 0x1D4
+#define DSI_PHY_ANA_PWR_CTRL 0x1E0
+#define DSI_PHY_ANA_CTRL0 0x1E4
+#define DSI_PHY_ANA_CTRL1 0x1E8
+
+//DSI_CTRL_0 0x0
+#define CFG_SOFT_RST BIT(31)
+#define CFG_SOFT_RST_REG BIT(30)
+#define CFG_CLR_PHY_FIFO BIT(29)
+#define CFG_RST_TXLP BIT(28)
+#define CFG_RST_CPU BIT(27)
+#define CFG_RST_CPN BIT(26)
+#define CFG_RST_VPN BIT(24)
+#define CFG_DSI_PHY_RST BIT(23)
+#define CFG_VPN_TX_EN BIT(8)
+#define CFG_VPN_SLV BIT(4)
+#define CFG_CPN_EN BIT(2)
+#define CFG_VPN_EN BIT(0)
+
+//DSI_CTRL_1 0x4
+#define CFG_EOTP_EN BIT(8)
+
+//DSI_IRQ_ST 0x10
+#define IRQ_RX_ERR BIT(25)
+#define IRQ_RX_TRG3 BIT(7)
+#define IRQ_RX_TRG2 BIT(6)
+#define IRQ_RX_TRG1 BIT(5)
+#define IRQ_RX_TRG0 BIT(4)
+#define IRQ_RX_PKT BIT(2)
+
+#ifdef CONFIG_SPACEMIT_FPGA
+//DSI_FPGA_PHY_CTRL_0 0x18
+#define CFG_DPHY_RSETZ 0
+#define CFG_DPHY_SHUTDOWN 1
+#define CFG_DPHY_RSTZCAL 2
+#define CFG_DPHY_TXRXZ 3
+#define CFG_DPHY_MASSLVZ 4
+#define CFG_DPHY_ENABLE0 5
+#define CFG_DPHY_ENABLE1 6
+#define CFG_DPHY_ENABLECLK 7
+#define CFG_DPHY_HSREQ_LANECLK 8
+#define CFG_DPHY_HSREQ_LANE0 9
+#define CFG_DPHY_HSREQ_LANE1 10
+#define CFG_DPHY_HSREQ_LANE2 11
+#define CFG_DPHY_HSREQ_LANE3 12
+#define CFG_DPHY_TXRX_BYTECLK_REV 13
+#define CFG_DPHY_FCLK_REV 14
+
+//DSI_FPGA_PHY_CTRL_1 0x1C
+#define CFG_DPHY_TESTCLK 0
+#define CFG_DPHY_TESTCLR 1
+#define CFG_DPHY_TESTEN 2
+#define CFG_DPHY_TXRXZ 3
+#define CFG_DPHY_TESTDIN 8
+#define CFG_DPHY_TESTDOUT 16
+#define CFG_DPHY_LOCK 24
+#endif
+
+//DSI_CPU_CMD_0 0x20
+#define CFG_CPU_CMD_REQ BIT(31)
+#define CFG_CPU_SP BIT(30)
+#define CFG_CPU_TURN BIT(29)
+#define CFG_CPU_TXLP BIT(27)
+#define CFG_CPU_WC_SHIFT 0
+
+//DSI_CPU_CMD_1 0x24
+#define CFG_TXLP_LPDT_SHIFT 20
+
+#define CFG_TXLP_LPDT_MASK (0xF << CFG_TXLP_LPDT_SHIFT)
+
+//DSI_CPU_CMD_3 0x2C
+#define CFG_CPU_DAT_REQ BIT(31)
+#define CFG_CPU_DAT_RW BIT(30)
+#define CFG_CPU_DAT_ADDR_SHIFT 16
+
+//DSI_CPN_CMD 0x50
+#define CFG_CPN_TE_EN_SHIFT 28
+#define CFG_CPN_RGB_TYPE_SHIFT 24
+#define CFG_CPN_BURST_MODE_SHIFT 3
+#define CFG_CPN_FIRSTP_SEL_SHIFT 2
+#define CFG_CPN_DMA_DIS_SHIFT 1
+#define CFG_CPN_ADDR0_EN_SHIFT 0
+
+//DSI_CPN_CTRL_1 0X58
+#define CFG_CPN_PKT_CNT_SHIFT 16
+#define CFG_CPN_FIFO_FULL_LEVEL_SHIFT 0
+
+//DSI_RX_PKT_ST_0 0x60
+#define CFG_RX_PKT0_PTR_SHIFT 16
+#define CFG_RX_PKT0_PTR_MASK (0x3F << CFG_RX_PKT0_PTR_SHIFT)
+
+//DSI_RX_PKT_CTRL 0x70
+#define CFG_RX_PKT_RD_REQ BIT(31)
+#define CFG_RX_PKT_RD_PTR_SHIFT 16
+#define CFG_RX_PKT_RD_PTR_MASK (0x3F << CFG_RX_PKT_RD_PTR_SHIFT)
+#define CFG_RX_PKT_RD_DATA_SHIFT 0
+#define CFG_RX_PKT_RD_DATA_MASK (0x3F << CFG_RX_PKT_RD_DATA_SHIFT)
+
+//DSI_RX_PKT_CTRL_1 0x74
+#define CFG_RX_PKT_BCNT_SHIFT 0
+#define CFG_RX_PKT_BCNT_MASK (0xff << CFG_RX_PKT_BCNT_SHIFT)
+
+//DSI_LCD_BDG_CTRL0 0x84
+#define CFG_VPN_FIFO_AFULL_CNT_SHIT 16
+#define CFG_VPN_FIFO_AFULL_CNT_MASK (0xfff << CFG_VPN_FIFO_AFULL_CNT_SHIT)
+#define CFG_VPN_FIFO_AFULL_BYPASS BIT(6)
+#define CFG_CPN_VSYNC_EDGE_SHIFT 5
+#define CFG_CPN_VSYNC_EDGE_MASK (1 << CFG_CPN_VSYNC_EDGE_SHIFT)
+#define CFG_CPN_TE_EDGE_SHIFT 4
+#define CFG_CPN_TE_EDGE_MASK (1 << CFG_CPN_TE_EDGE_SHIFT)
+#define CFG_CPN_TE_MODE_SHIFT 2
+#define CFG_CPN_TE_MODE_MASK (3 << CFG_CPN_TE_MODE_SHIFT)
+#define CFG_PIXEL_SWAP BIT(1)
+#define CFG_SPLIT_EN BIT(0)
+
+//DSI_LCD_BDG_CTRL1 0x88
+#define CFG_CPN_TE_DLY_CNT_SHIFT 16
+#define CFG_CPN_TE_LINE_CNT_SHIFT 0
+
+//DSI_VPN_CTRL_1 0x104
+#define CFG_VPN_VSYNC_RST_EN_SHIFT 31
+#define CFG_VPN_AUTO_WC_DIS_SHIFT 27
+#define CFG_VPN_HACT_WC_EN_SHIFT 26
+#define CFG_VPN_TIMING_CHECK_DIS_SHIFT 25
+#define CFG_VPN_AUTO_DLY_DIS_SHIFT 24
+#define CFG_VPN_HLP_PKT_EN_SHIFT 22
+#define CFG_VPN_HEX_PKT_EN_SHIFT 21
+#define CFG_VPN_HFP_PKT_EN_SHIFT 20
+#define CFG_VPN_HBP_PKT_EN_SHIFT 18
+#define CFG_VPN_HSE_PKT_EN_SHIFT 17
+#define CFG_VPN_HSA_PKT_EN_SHIFT 16
+#define CFG_VPN_HEX_SLOT_EN_SHIFT 14
+#define CFG_VPN_LAST_LINE_TURN_SHIFT 10
+#define CFG_VPN_LPM_FRAME_EN_SHIFT 9
+#define CFG_VPN_BURST_MODE_SHIFT 2
+#define CFG_VPN_BURST_MODE_MASK (0x3 << CFG_VPN_BURST_MODE_SHIFT)
+#define CFG_VPN_RGB_TYPE_SHIFT 0
+#define CFG_VPN_RGB_TYPE_MASK (0x3 << CFG_VPN_RGB_TYPE_SHIFT)
+
+//DSI_PHY_CTRL_1 0x184
+#define CFG_DPHY_ADD_VALID BIT(17)
+#define CFG_DPHY_VDD_VALID BIT(16)
+#define CFG_DPHY_ULPS_DATA BIT(2)
+#define CFG_DPHY_ULPS_CLK BIT(1)
+#define CFG_DPHY_CONT_CLK BIT(0)
+
+//DSI_PHY_CTRL_2 0x188
+#define CFG_DPHY_HSTX_RX BIT(14)
+#define CFG_DPHY_LANE_MAP_SHIFT 12
+#define CFG_DPHY_LANE_EN_SHIFT 4
+#define CFG_DPHY_FORCE_BTA BIT(0)
+
+#define CFG_DPHY_LANE_MAP_MASK (0x3 << CFG_DPHY_LANE_MAP_SHIFT)
+#define CFG_DPHY_LANE_EN_MASK (0xF << CFG_DPHY_LANE_EN_SHIFT)
+
+//DSI_PHY_TIME_0 0x1C0
+#define CFG_DPHY_TIME_HS_EXIT_SHIFT 24
+#define CFG_DPHY_TIME_HS_TRAIL_SHIFT 16
+#define CFG_DPHY_TIME_HS_ZERO_SHIFT 8
+#define CFG_DPHY_TIME_HS_PREP_SHIFT 0
+
+#define CFG_DPHY_TIME_HS_EXIT_MASK (0xFF << CFG_DPHY_TIME_HS_EXIT_SHIFT)
+#define CFG_DPHY_TIME_HS_TRAIL_MASK (0xFF << CFG_DPHY_TIME_HS_TRAIL_SHIFT)
+#define CFG_DPHY_TIME_HS_ZERO_MASK (0xFF << CFG_DPHY_TIME_HS_ZERO_SHIFT)
+#define CFG_DPHY_TIME_HS_PREP_MASK (0xFF << CFG_DPHY_TIME_HS_PREP_SHIFT)
+
+//DSI_PHY_TIME_1 0x1C4
+#define CFG_DPHY_TIME_TA_GET_SHIFT 24
+#define CFG_DPHY_TIME_TA_GO_SHIFT 16
+#define CFG_DPHY_TIME_WAKEUP_SHIFT 0
+
+#define CFG_DPHY_TIME_TA_GET_MASK (0xFF << CFG_DPHY_TIME_TA_GET_SHIFT)
+#define CFG_DPHY_TIME_TA_GO_MASK (0xFF << CFG_DPHY_TIME_TA_GO_SHIFT)
+#define CFG_DPHY_TIME_WAKEUP_MASK (0xFFFF << CFG_DPHY_TIME_WAKEUP_SHIFT)
+
+//DSI_PHY_TIME_2 0x1C8
+#define CFG_DPHY_TIME_CLK_EXIT_SHIFT 24
+#define CFG_DPHY_TIME_CLK_TRAIL_SHIFT 16
+#define CFG_DPHY_TIME_CLK_ZERO_SHIFT 8
+#define CFG_DPHY_TIME_CLK_LPX_SHIFT 0
+
+#define CFG_DPHY_TIME_CLK_EXIT_MASK (0xFF << CFG_DPHY_TIME_CLK_EXIT_SHIFT)
+#define CFG_DPHY_TIME_CLK_TRAIL_MASK (0xFF << CFG_DPHY_TIME_CLK_TRAIL_SHIFT)
+#define CFG_DPHY_TIME_CLK_ZERO_MASK (0xFF << CFG_DPHY_TIME_CLK_ZERO_SHIFT)
+#define CFG_DPHY_TIME_CLK_LPX_MASK (0xFF << CFG_DPHY_TIME_CLK_LPX_SHIFT)
+
+//DSI_PHY_TIME_3 0x1CC
+#define CFG_DPHY_TIME_LPX_SHIFT 8
+#define CFG_DPHY_TIME_REQRDY_SHIFT 0
+
+#define CFG_DPHY_TIME_LPX_MASK (0xFF << CFG_DPHY_TIME_LPX_SHIFT)
+#define CFG_DPHY_TIME_REQRDY_MASK (0xFF << CFG_DPHY_TIME_REQRDY_SHIFT)
+
+//DSI_PHY_ANA_PWR_CTRL 0x1E0
+#define CFG_DPHY_ANA_RESET BIT(8)
+#define CFG_DPHY_ANA_PU BIT(0)
+
+//DSI_PHY_ANA_CTRL1 0x1E8
+#ifdef CONFIG_SPACEMIT_FPGA
+#define CFG_CLK_SEL BIT(23)
+#else
+#define CFG_CLK_SEL BIT(21)
+#endif
+#define CFG_CLK_DIV2 BIT(11)
+
+
+/*dphy timming*/
+#define HS_PREP_CONSTANT_DEFAULT 40
+#define HS_PREP_UI_DEFAULT 4
+#define HS_ZERO_CONSTANT_DEFAULT 145
+#define HS_ZERO_UI_DEFAULT 10
+#define HS_TRAIL_CONSTANT_DEFAULT 60
+#define HS_TRAIL_UI_DEFAULT 4
+#define HS_EXIT_CONSTANT_DEFAULT 100
+#define HS_EXIT_UI_DEFAULT 0
+#define CK_ZERO_CONSTANT_DEFAULT 300
+#define CK_ZERO_UI_DEFAULT 0
+#define CK_TRAIL_CONSTANT_DEFAULT 60
+#define CK_TRAIL_UI_DEFAULT 0
+#define REQ_READY_DEFAULT 0x3C
+#define WAKEUP_CONSTANT_DEFAULT 1000000
+#define WAKEUP_UI_DEFAULT 0
+#define LPX_CONSTANT_DEFAULT 60
+#define LPX_UI_DEFAULT 0
+
+
+static inline uint32_t dsi_read(void __iomem *addr, uint32_t offset)
+{
+ DRM_DEBUG("DSI_READ [0x%x] = 0x%x\n", offset, __raw_readl(addr + offset));
+ return __raw_readl(addr + offset);
+}
+
+static inline void dsi_write(void __iomem *addr, uint32_t offset, uint32_t data)
+{
+ DRM_DEBUG("DSI_WRITE [0x%x] = 0x%x\n", 0xd421a800 + offset, data);
+ __raw_writel(data, (addr + offset));
+}
+
+static inline void dsi_set_bits(void __iomem *addr, uint32_t offset, uint32_t bits)
+{
+ dsi_write(addr, offset, (dsi_read(addr, offset) | bits));
+}
+
+static inline void dsi_clear_bits(void __iomem *addr, uint32_t offset, uint32_t bits)
+{
+ dsi_write(addr, offset, (dsi_read(addr, offset) & ~bits));
+}
+
+static inline void dsi_write_bits(void __iomem *addr, uint32_t offset, uint32_t mask, uint32_t value)
+{
+ uint32_t tmp = 0;
+
+ tmp = dsi_read(addr, offset);
+ tmp &= ~mask;
+ tmp |= value;
+ dsi_write(addr, offset, tmp);
+}
+
+#endif /*_SPACEMIT_DSI_HW_H_*/
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/atomic.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_bridge.h>
+#include <linux/delay.h>
+#include <drm/display/drm_dp_aux_bus.h>
+#include <drm/display/drm_dp_helper.h>
+
+#define IT8911_DSI_DRIVER_NAME "spacemit-edp-drv"
+#define EDID_SEG_SIZE 256
+#define EDID_LEN 16
+
+#define MIPI_DSI_1920x1080 1
+#define MIPI_DSI_1920x1200 0
+
+// #define _test_pattern_
+// #define _read_edid_
+// #define _uart_debug_
+#define _eDP_2G7_
+#define _link_train_enable_
+
+#define _MIPI_Lane_ 4 // 4 3 2 1
+#define _MIPI_data_PN_Swap_En 0xF0
+#define _MIPI_data_PN_Swap_Dis 0x00
+#define _MIPI_data_PN_ _MIPI_data_PN_Swap_Dis
+#define _Nvid 0 // default 0: 0x0080
+static int Nvid_Val[] = {0x0080, 0x0800};
+
+#define _No_swap_ 0x00 // default
+#define _MIPI_data_3210_ 0 // default
+#define _MIPI_data_0123_ 21
+#define _MIPI_data_2103_ 20
+#define _MIPI_data_sequence_ _No_swap_
+
+#define eDP_lane 2
+#define PCR_PLL_PREDIV 0x40
+
+#define LT8911_LOW 1
+#define LT8911_HIGH 0
+
+static int MIPI_Timing[] =
+// hfp, hs, hbp, hact, htotal, vfp, vs, vbp, vact, vtotal, pixel_CLK/10000
+
+// 1920x1080
+#if MIPI_DSI_1920x1080
+// {48, 32, 200, 1920, 2200, 3, 6, 31, 1080, 1120, 14784}; // boe config for linux
+{48, 32, 200, 1920, 2200, 3, 6, 31, 1080, 1120, 14285}; // boe config for linux
+#endif
+
+// 1920x1200
+#if MIPI_DSI_1920x1200
+// {16, 16, 298, 1920, 2250, 3, 14, 19, 1200, 1236, 16684}; // boe config for linux
+{16, 16, 298, 1920, 2250, 3, 14, 19, 1200, 1236, 15360}; // boe config for linux
+// {16, 16, 298, 1920, 2250, 3, 14, 19, 1200, 1236, 14285}; // boe config for linux
+#endif
+
+#define _8bit_
+
+enum {
+ hfp = 0,
+ hs,
+ hbp,
+ hact,
+ htotal,
+ vfp,
+ vs,
+ vbp,
+ vact,
+ vtotal,
+ pclk_10khz
+};
+
+u32 EDID_DATA[128] = { 0 };
+u32 EDID_Timing[11] = { 0 };
+bool EDID_Reply = 0;
+
+bool ScrambleMode = 0;
+
+static const struct drm_display_mode lt8911exb_panel_modes[] = {
+// 1920x1080
+#if MIPI_DSI_1920x1080
+ {
+ .clock = 142857143 / 1000,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 48,
+ .hsync_end = 1920 + 48 + 200,
+ .htotal = 1920 + 48 + 200 + 32,
+ .vdisplay = 1080,
+ .vsync_start = 1080 + 3,
+ .vsync_end = 1080 + 3 + 31,
+ .vtotal = 1080 + 3 + 31 + 6,
+ },
+#endif
+
+// 1920x1200
+#if MIPI_DSI_1920x1200
+
+ {
+ .clock = 142857143 / 1000,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 16,
+ .hsync_end = 1920 + 16 + 298,
+ .htotal = 1920 + 16 + 298 + 16,
+ .vdisplay = 1200,
+ .vsync_start = 1200 + 3,
+ .vsync_end = 1200 + 3 + 19,
+ .vtotal = 1200 + 3 + 19 + 14,
+ },
+#endif
+
+};
+
+enum
+{
+ _Level0_ = 0, // 27.8 mA 0x83/0x00
+ _Level1_, // 26.2 mA 0x82/0xe0
+ _Level2_, // 24.6 mA 0x82/0xc0
+ _Level3_, // 23 mA 0x82/0xa0
+ _Level4_, // 21.4 mA 0x82/0x80
+ _Level5_, // 18.2 mA 0x82/0x40
+ _Level6_, // 16.6 mA 0x82/0x20
+ _Level7_, // 15 mA 0x82/0x00 // level 1
+ _Level8_, // 12.8mA 0x81/0x00 // level 2
+ _Level9_, // 11.2mA 0x80/0xe0 // level 3
+ _Level10_, // 9.6mA 0x80/0xc0 // level 4
+ _Level11_, // 8mA 0x80/0xa0 // level 5
+ _Level12_, // 6mA 0x80/0x80 // level 6
+};
+
+u8 Swing_Setting1[] = {0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x80};
+u8 Swing_Setting2[] = {0x00, 0xe0, 0xc0, 0xa0, 0x80, 0x40, 0x20, 0x00, 0x00, 0xe0, 0xc0, 0xa0, 0x80};
+
+u8 Level = _Level7_; // normal
+
+struct lt8911exb {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_connector connector;
+
+ struct regmap *regmap;
+
+ struct device_node *dsi0_node;
+ struct device_node *dsi1_node;
+ struct mipi_dsi_device *dsi0;
+ struct mipi_dsi_device *dsi1;
+
+ struct gpio_desc *reset_gpio; //reset
+ struct gpio_desc *enable_gpio; //power
+ struct gpio_desc *standby_gpio; //standby
+ struct gpio_desc *bl_gpio; //backlight
+
+ bool power_on;
+ bool sleep;
+
+ struct regulator_bulk_data supplies[2];
+
+ struct i2c_client *client;
+ struct drm_panel base;
+ struct mipi_dsi_device *dsi;
+
+ enum drm_connector_status status;
+
+ u8 edid_buf[EDID_SEG_SIZE];
+ u32 vic;
+
+ struct delayed_work init_work;
+ bool init_work_pending;
+};
+
+static const struct regmap_config lt8911exb_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+};
+
+static struct lt8911exb *panel_to_lt8911exb(struct drm_panel *panel)
+{
+ return container_of(panel, struct lt8911exb, base);
+}
+
+void lt8911exb_mipi_video_timing(struct lt8911exb *lt8911exb)
+{
+ __maybe_unused unsigned int tmp;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xd0);
+ regmap_write(lt8911exb->regmap, 0x0d, (MIPI_Timing[vtotal] / 256));
+ regmap_write(lt8911exb->regmap, 0x0e, (MIPI_Timing[vtotal] % 256)); //vtotal
+ regmap_write(lt8911exb->regmap, 0x0f, (MIPI_Timing[vact] / 256));
+ regmap_write(lt8911exb->regmap, 0x10, (MIPI_Timing[vact] % 256)); //vactive
+ regmap_write(lt8911exb->regmap, 0x11, (MIPI_Timing[htotal] / 256));
+ regmap_write(lt8911exb->regmap, 0x12, (MIPI_Timing[htotal] % 256)); //htotal
+ regmap_write(lt8911exb->regmap, 0x13, (MIPI_Timing[hact] / 256));
+ regmap_write(lt8911exb->regmap, 0x14, (MIPI_Timing[hact] % 256)); //hactive
+ regmap_write(lt8911exb->regmap, 0x15, (MIPI_Timing[vs] % 256)); //vsa
+ regmap_write(lt8911exb->regmap, 0x16, (MIPI_Timing[hs] % 256)); //hsa
+ regmap_write(lt8911exb->regmap, 0x17, (MIPI_Timing[vfp] / 256));
+ regmap_write(lt8911exb->regmap, 0x18, (MIPI_Timing[vfp] % 256)); //vfp
+ regmap_write(lt8911exb->regmap, 0x19, (MIPI_Timing[hfp] / 256));
+ regmap_write(lt8911exb->regmap, 0x1a, (MIPI_Timing[hfp] % 256)); //hfp
+
+#ifdef _uart_debug_
+ DRM_INFO("------\n");
+ DRM_INFO("MIPI_Timing[vtotal] / 256 = %d\n", MIPI_Timing[vtotal] / 256);
+ DRM_INFO("MIPI_Timing[vtotal] 256 = %d\n", MIPI_Timing[vtotal] % 256);
+ DRM_INFO("MIPI_Timing[vact] / 256 = %d\n", MIPI_Timing[vact] / 256);
+ DRM_INFO("MIPI_Timing[vact] 256 = %d\n", MIPI_Timing[vact] % 256);
+ DRM_INFO("MIPI_Timing[htotal] / 256 = %d\n", MIPI_Timing[htotal] / 256);
+ DRM_INFO("MIPI_Timing[htotal] 256 = %d\n", MIPI_Timing[htotal] % 256);
+ DRM_INFO("MIPI_Timing[hact] / 256 = %d\n", MIPI_Timing[hact] / 256);
+ DRM_INFO("MIPI_Timing[hact] 256 = %d\n", MIPI_Timing[hact] % 256);
+
+ DRM_INFO("MIPI_Timing[vs] 256 = %d\n", MIPI_Timing[vs] % 256);
+ DRM_INFO("MIPI_Timing[hs] 256 = %d\n", MIPI_Timing[hs] % 256);
+
+ DRM_INFO("MIPI_Timing[vfp] / 256 = %d\n", MIPI_Timing[vfp] / 256);
+ DRM_INFO("MIPI_Timing[vfp] 256 = %d\n", MIPI_Timing[vfp] % 256);
+ DRM_INFO("MIPI_Timing[hfp] / 256 = %d\n", MIPI_Timing[hfp] / 256);
+ DRM_INFO("MIPI_Timing[hfp] 256 = %d\n", MIPI_Timing[hfp] % 256);
+ DRM_INFO("------\n");
+
+ regmap_read(lt8911exb->regmap, 0x0d, &tmp);
+ DRM_DEBUG_ATOMIC("0x0d = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0e, &tmp);
+ DRM_DEBUG_ATOMIC("0x0e = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0f, &tmp);
+ DRM_DEBUG_ATOMIC("0x0f = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x10, &tmp);
+ DRM_DEBUG_ATOMIC("0x10 = %d\n",tmp);
+
+ regmap_read(lt8911exb->regmap, 0x11, &tmp);
+ DRM_DEBUG_ATOMIC("0x11 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x12, &tmp);
+ DRM_DEBUG_ATOMIC("0x12 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x13, &tmp);
+ DRM_DEBUG_ATOMIC("0x13 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x14, &tmp);
+ DRM_DEBUG_ATOMIC("0x14 = %d\n",tmp);
+
+
+ regmap_read(lt8911exb->regmap, 0x15, &tmp);
+ DRM_DEBUG_ATOMIC("0x15 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x16, &tmp);
+ DRM_DEBUG_ATOMIC("0x16 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x17, &tmp);
+ DRM_DEBUG_ATOMIC("0x17 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x18, &tmp);
+ DRM_DEBUG_ATOMIC("0x18 = %d\n",tmp);
+
+ regmap_read(lt8911exb->regmap, 0x19, &tmp);
+ DRM_DEBUG_ATOMIC("0x19 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x1a, &tmp);
+ DRM_DEBUG_ATOMIC("0x1a = %d\n",tmp);
+#endif
+}
+
+void lt8911exb_edp_video_cfg(struct lt8911exb *lt8911exb)
+{
+ __maybe_unused unsigned int tmp;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xa8);
+ regmap_write(lt8911exb->regmap, 0x2d, 0x88); // MSA from register
+ regmap_write(lt8911exb->regmap, 0x05, (MIPI_Timing[htotal] / 256));
+ regmap_write(lt8911exb->regmap, 0x06, (MIPI_Timing[htotal] % 256));
+ regmap_write(lt8911exb->regmap, 0x07, ((MIPI_Timing[hs] + MIPI_Timing[hbp]) / 256 ));
+ regmap_write(lt8911exb->regmap, 0x08, ((MIPI_Timing[hs] + MIPI_Timing[hbp]) % 256));
+ regmap_write(lt8911exb->regmap, 0x09, (MIPI_Timing[hs] / 256));
+ regmap_write(lt8911exb->regmap, 0x0a, (MIPI_Timing[hs] % 256));
+ regmap_write(lt8911exb->regmap, 0x0b, (MIPI_Timing[hact] / 256));
+ regmap_write(lt8911exb->regmap, 0x0c, (MIPI_Timing[hact] % 256));
+ regmap_write(lt8911exb->regmap, 0x0d, (MIPI_Timing[vtotal] / 256));
+ regmap_write(lt8911exb->regmap, 0x0e, (MIPI_Timing[vtotal] % 256));
+ regmap_write(lt8911exb->regmap, 0x11, ((MIPI_Timing[vs] + MIPI_Timing[vbp]) / 256));
+ regmap_write(lt8911exb->regmap, 0x12, ((MIPI_Timing[vs] + MIPI_Timing[vbp]) % 256));
+ regmap_write(lt8911exb->regmap, 0x14, (MIPI_Timing[vs] % 256));
+ regmap_write(lt8911exb->regmap, 0x15, (MIPI_Timing[vact] / 256));
+ regmap_write(lt8911exb->regmap, 0x16, (MIPI_Timing[vact] % 256));
+
+#ifdef _uart_debug_
+ DRM_INFO("------\n");
+ DRM_INFO("(u8)( MIPI_Timing[htotal] / 256 ) = %d\n", (MIPI_Timing[htotal] / 256));
+ DRM_INFO("(u8)( MIPI_Timing[htotal] 256 ) = %d\n", (MIPI_Timing[htotal] % 256));
+ DRM_INFO("(u8)( ( MIPI_Timing[hs] + MIPI_Timing[hbp] ) / 256 ) = %d\n", ((MIPI_Timing[hs] + MIPI_Timing[hbp]) / 256));
+ DRM_INFO("(u8)( ( MIPI_Timing[hs] + MIPI_Timing[hbp] ) 256 ) = %d\n", ((MIPI_Timing[hs] + MIPI_Timing[hbp]) % 256));
+ DRM_INFO("(u8)( MIPI_Timing[hs] / 256 ) = %d\n", (MIPI_Timing[hs] / 256));
+ DRM_INFO(" (u8)( MIPI_Timing[hs] 256 ) = %d\n", (MIPI_Timing[hs] % 256));
+ DRM_INFO(" (u8)( MIPI_Timing[hact] / 256 ) = %d\n", (MIPI_Timing[hact] / 256));
+ DRM_INFO("(u8)( MIPI_Timing[hact] 256 ) = %d\n", (MIPI_Timing[hact] % 256));
+
+ DRM_INFO("(u8)( ( MIPI_Timing[vs] + MIPI_Timing[vbp] ) / 256 ) = %d\n", ((MIPI_Timing[vs] + MIPI_Timing[vbp]) / 256));
+ DRM_INFO(" (u8)( ( MIPI_Timing[vs] + MIPI_Timing[vbp] ) 256 ) = %d\n", ((MIPI_Timing[vs] + MIPI_Timing[vbp]) % 256));
+
+ DRM_INFO(" (u8)( MIPI_Timing[vs] 256 ) = %d\n", (MIPI_Timing[vs] % 256));
+ DRM_INFO(" (u8)( MIPI_Timing[vact] / 256 ) = %d\n", (MIPI_Timing[vact] / 256));
+ DRM_INFO("(u8)( MIPI_Timing[vact] 256 ) = %d\n", (MIPI_Timing[vact] % 256));
+ DRM_INFO("------\n");
+
+ regmap_read(lt8911exb->regmap, 0x05, &tmp);
+ DRM_DEBUG_ATOMIC("0x05 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x06, &tmp);
+ DRM_DEBUG_ATOMIC("0x06 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x07, &tmp);
+ DRM_DEBUG_ATOMIC("0x07 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x08, &tmp);
+ DRM_DEBUG_ATOMIC("0x08 = %d\n",tmp);
+
+ regmap_read(lt8911exb->regmap, 0x09, &tmp);
+ DRM_DEBUG_ATOMIC("0x09 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0a, &tmp);
+ DRM_DEBUG_ATOMIC("0x0a = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0b, &tmp);
+ DRM_DEBUG_ATOMIC("0x0b = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0c, &tmp);
+ DRM_DEBUG_ATOMIC("0x0c = %d\n",tmp);
+
+
+ regmap_read(lt8911exb->regmap, 0x0d, &tmp);
+ DRM_DEBUG_ATOMIC("0x0d = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x0e, &tmp);
+ DRM_DEBUG_ATOMIC("0x0e = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x11, &tmp);
+ DRM_DEBUG_ATOMIC("0x11 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x12, &tmp);
+ DRM_DEBUG_ATOMIC("0x12 = %d\n",tmp);
+
+ regmap_read(lt8911exb->regmap, 0x14, &tmp);
+ DRM_DEBUG_ATOMIC("0x14 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x15, &tmp);
+ DRM_DEBUG_ATOMIC("0x15 = %d\n",tmp);
+ regmap_read(lt8911exb->regmap, 0x16, &tmp);
+ DRM_DEBUG_ATOMIC("0x16 = %d\n",tmp);
+#endif
+}
+
+void lt8911exb_read_edid(struct lt8911exb *lt8911exb)
+{
+#ifdef _read_edid_
+ u8 i, j;
+ unsigned int reg;
+
+ DRM_INFO("%s()\n", __func__);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xac );
+ regmap_write(lt8911exb->regmap, 0x00, 0x20 ); //Soft Link train
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6 );
+ regmap_write(lt8911exb->regmap, 0x2a, 0x01 );
+
+ /*set edid offset addr*/
+ regmap_write(lt8911exb->regmap, 0x2b, 0x40 ); //CMD
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00 ); //addr[15:8]
+ regmap_write(lt8911exb->regmap, 0x2b, 0x50 ); //addr[7:0]
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00 ); //data lenth
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00 ); //data lenth
+ regmap_write(lt8911exb->regmap, 0x2c, 0x00 ); //start Aux read edid
+
+ mdelay(20); //more than 10ms
+ regmap_read(lt8911exb->regmap, 0x25, ®);
+ DRM_INFO("lt8911exb_read_edid 0x25 0x%x\n", reg);
+
+ if( ( reg & 0x0f ) == 0x0c )
+ {
+ for( j = 0; j < 8; j++ )
+ {
+ if( j == 7 )
+ {
+ regmap_write(lt8911exb->regmap, 0x2b, 0x10 ); //MOT
+ }else
+ {
+ regmap_write(lt8911exb->regmap, 0x2b, 0x50 );
+ }
+
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00 );
+ regmap_write(lt8911exb->regmap, 0x2b, 0x50 );
+ regmap_write(lt8911exb->regmap, 0x2b, 0x0f );
+ regmap_write(lt8911exb->regmap, 0x2c, 0x00 ); //start Aux read edid
+ mdelay(50); //more than 50ms
+
+ regmap_read(lt8911exb->regmap, 0x39, ®);
+ DRM_INFO("lt8911exb_read_edid 0x39 0x%x\n", reg);
+ if (reg == 0x31)
+ {
+ regmap_read(lt8911exb->regmap, 0x2b, ®);
+ DRM_INFO("lt8911exb_read_edid 0x2b 0x%x\n", reg);
+ for( i = 0; i < 16; i++ )
+ {
+ regmap_read(lt8911exb->regmap, 0x2b, ®);
+ EDID_DATA[j * 16 + i] = reg;
+ }
+
+ EDID_Reply = 1;
+ }else
+ {
+ EDID_Reply = 0;
+ return;
+ }
+ }
+
+ // for( i = 0; i < 128; i++ ) //print edid data
+ // {
+ // if( ( i % 16 ) == 0 )
+ // {
+ // DRM_INFO( "\n" );
+ // }
+ // DRM_INFO( "%x", EDID_DATA[i] );
+ // }
+
+
+ EDID_Timing[hfp] = (EDID_DATA[0x41] & 0xC0) * 4 + EDID_DATA[0x3e];
+ EDID_Timing[hs] = (EDID_DATA[0x41] & 0x30) * 16 + EDID_DATA[0x3f];
+ EDID_Timing[hbp] = ((EDID_DATA[0x3a] & 0x0f) * 0x100 + EDID_DATA[0x39]) - ((EDID_DATA[0x41] & 0x30) * 16 + EDID_DATA[0x3f]) - ((EDID_DATA[0x41] & 0xC0 ) * 4 + EDID_DATA[0x3e]);
+ EDID_Timing[hact] = (EDID_DATA[0x3a] & 0xf0) * 16 + EDID_DATA[0x38];
+ EDID_Timing[htotal] = (EDID_DATA[0x3a] & 0xf0) * 16 + EDID_DATA[0x38] + ((EDID_DATA[0x3a] & 0x0f) * 0x100 + EDID_DATA[0x39]);
+ EDID_Timing[vfp] = (EDID_DATA[0x41] & 0x0c) * 4 + (EDID_DATA[0x40] & 0xf0 ) / 16;
+ EDID_Timing[vs] = (EDID_DATA[0x41] & 0x03) * 16 + (EDID_DATA[0x40] & 0x0f );
+ EDID_Timing[vbp] = ((EDID_DATA[0x3d] & 0x03) * 0x100 + EDID_DATA[0x3c]) - ((EDID_DATA[0x41] & 0x03) * 16 + (EDID_DATA[0x40] & 0x0f)) - ((EDID_DATA[0x41] & 0x0c) * 4 + (EDID_DATA[0x40] & 0xf0 ) / 16);
+ EDID_Timing[vact] = (EDID_DATA[0x3d] & 0xf0) * 16 + EDID_DATA[0x3b];
+ EDID_Timing[vtotal] = (EDID_DATA[0x3d] & 0xf0 ) * 16 + EDID_DATA[0x3b] + ((EDID_DATA[0x3d] & 0x03) * 0x100 + EDID_DATA[0x3c]);
+ EDID_Timing[pclk_10khz] = EDID_DATA[0x37] * 0x100 + EDID_DATA[0x36];
+ DRM_INFO( "eDP Timing = { H_FP / H_pluse / H_BP / H_act / H_tol / V_FP / V_pluse / V_BP / V_act / V_tol / D_CLK };" );
+ DRM_INFO( "eDP Timing = { %d %d %d %d %d %d %d %d %d %d %d };\n",
+ (u32)EDID_Timing[hfp],(u32)EDID_Timing[hs],(u32)EDID_Timing[hbp],(u32)EDID_Timing[hact],(u32)EDID_Timing[htotal],
+ (u32)EDID_Timing[vfp],(u32)EDID_Timing[vs],(u32)EDID_Timing[vbp],(u32)EDID_Timing[vact],(u32)EDID_Timing[vtotal],(u32)EDID_Timing[pclk_10khz]);
+ }
+
+ return;
+
+#endif
+}
+
+void lt8911exb_setup(struct lt8911exb *lt8911exb)
+{
+ u8 i;
+ u8 pcr_pll_postdiv;
+ u8 pcr_m;
+ u16 Temp16;
+ u32 chip_read = 0x00;
+
+ DRM_DEBUG("\r\n lt8911exb_setup");
+
+ /* init */
+ regmap_write(lt8911exb->regmap, 0xff, 0x81); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x08, 0x7f); // i2c over aux issue
+ regmap_write(lt8911exb->regmap, 0x49, 0xff); // enable 0x87xx
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x82); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x5a, 0x0e); // GPIO test output
+
+ //for power consumption//
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x05, 0x06);
+ regmap_write(lt8911exb->regmap, 0x43, 0x00);
+ regmap_write(lt8911exb->regmap, 0x44, 0x1f);
+ regmap_write(lt8911exb->regmap, 0x45, 0xf7);
+ regmap_write(lt8911exb->regmap, 0x46, 0xf6);
+ regmap_write(lt8911exb->regmap, 0x49, 0x7f);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x82);
+#if (eDP_lane == 2)
+ {
+ regmap_write(lt8911exb->regmap, 0x12, 0x33);
+ }
+#elif (eDP_lane == 1)
+ {
+ regmap_write(lt8911exb->regmap, 0x12, 0x11);
+ }
+#endif
+
+ /* mipi Rx analog */
+ regmap_write(lt8911exb->regmap, 0xff, 0x82); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x32, 0x51);
+ regmap_write(lt8911exb->regmap, 0x35, 0x22); //EQ current 0x22/0x42/0x62/0x82/0xA2/0xC2/0xe2
+ regmap_write(lt8911exb->regmap, 0x3a, 0x77); //EQ 12.5db
+ regmap_write(lt8911exb->regmap, 0x3b, 0x77); //EQ 12.5db
+
+ regmap_write(lt8911exb->regmap, 0x4c, 0x0c);
+ regmap_write(lt8911exb->regmap, 0x4d, 0x00);
+
+ /* dessc_pcr pll analog */
+ regmap_write(lt8911exb->regmap, 0xff, 0x82); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x6a, 0x40);
+ regmap_write(lt8911exb->regmap, 0x6b, PCR_PLL_PREDIV);
+
+ Temp16 = MIPI_Timing[pclk_10khz];
+
+ if (MIPI_Timing[pclk_10khz] < 8800) {
+ regmap_write(lt8911exb->regmap, 0x6e, 0x82); //0x44:pre-div = 2 ,pixel_clk=44~ 88MHz
+ pcr_pll_postdiv = 0x08;
+ } else if (MIPI_Timing[pclk_10khz] < 17600){
+ regmap_write(lt8911exb->regmap, 0x6e, 0x81); //0x40:pre-div = 1, pixel_clk =88~176MHz
+ pcr_pll_postdiv = 0x04;
+ } else {
+ regmap_write(lt8911exb->regmap, 0x6e, 0x80); //0x40:pre-div = 0, pixel_clk =176~200MHz
+ pcr_pll_postdiv = 0x02;
+ }
+
+ pcr_m = (u8)(Temp16 * pcr_pll_postdiv / 25 / 100);
+
+ /* dessc pll digital */
+ regmap_write(lt8911exb->regmap, 0xff, 0x85); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0xa9, 0x31);
+ regmap_write(lt8911exb->regmap, 0xaa, 0x17);
+ regmap_write(lt8911exb->regmap, 0xab, 0xba);
+ regmap_write(lt8911exb->regmap, 0xac, 0xe1);
+ regmap_write(lt8911exb->regmap, 0xad, 0x47);
+ regmap_write(lt8911exb->regmap, 0xae, 0x01);
+ regmap_write(lt8911exb->regmap, 0xae, 0x11);
+
+ /* Digital Top */
+ regmap_write(lt8911exb->regmap, 0xff, 0x85); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0xc0, 0x01); //select mipi Rx
+#ifdef _6bit_
+ regmap_write(lt8911exb->regmap, 0xb0, 0xd0); //enable dither
+#else
+ regmap_write(lt8911exb->regmap, 0xb0, 0x00); // disable dither
+#endif
+
+ /* mipi Rx Digital */
+ regmap_write(lt8911exb->regmap, 0xff, 0xd0); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x00, _MIPI_data_PN_ + _MIPI_Lane_ % 4); // 0: 4 Lane / 1: 1 Lane / 2 : 2 Lane / 3: 3 Lane
+ regmap_write(lt8911exb->regmap, 0x02, 0x08); //settle
+ regmap_write(lt8911exb->regmap, 0x03, _MIPI_data_sequence_); // default is 0x00
+ regmap_write(lt8911exb->regmap, 0x08, 0x00);
+// regmap_write(lt8911exb->regmap, 0x0a, 0x12); //pcr mode
+
+ regmap_write(lt8911exb->regmap, 0x0c, 0x80); //fifo position
+ regmap_write(lt8911exb->regmap, 0x1c, 0x80); //fifo position
+
+ // hs mode:MIPI行采样;vs mode:MIPI帧采样
+ regmap_write(lt8911exb->regmap, 0x24, 0x70); // 0x30 [3:0] line limit //pcr mode( de hs vs)
+
+ regmap_write(lt8911exb->regmap, 0x31, 0x0a);
+
+ /*stage1 hs mode*/
+ regmap_write(lt8911exb->regmap, 0x25, 0x90); // 0x80 // line limit
+ regmap_write(lt8911exb->regmap, 0x2a, 0x3a); // 0x04 // step in limit
+ regmap_write(lt8911exb->regmap, 0x21, 0x4f); // hs_step
+ regmap_write(lt8911exb->regmap, 0x22, 0xff);
+
+ /*stage2 de mode*/
+ regmap_write(lt8911exb->regmap, 0x0a, 0x02); //de adjust pre line
+ regmap_write(lt8911exb->regmap, 0x38, 0x02); //de_threshold 1
+ regmap_write(lt8911exb->regmap, 0x39, 0x04); //de_threshold 2
+ regmap_write(lt8911exb->regmap, 0x3a, 0x08); //de_threshold 3
+ regmap_write(lt8911exb->regmap, 0x3b, 0x10); //de_threshold 4
+
+ regmap_write(lt8911exb->regmap, 0x3f, 0x04); //de_step 1
+ regmap_write(lt8911exb->regmap, 0x40, 0x08); //de_step 2
+ regmap_write(lt8911exb->regmap, 0x41, 0x10); //de_step 3
+ regmap_write(lt8911exb->regmap, 0x42, 0x60); //de_step 4
+
+ /*stage2 hs mode*/
+ // regmap_write(lt8911exb->regmap, 0x1e, 0x0A); //regmap_write(lt8911exb->regmap, 0x1e, 0x01 ); // 0x11
+ DRM_DEBUG("\r\n lt8911exb_setup 0X1e 0x0a");
+ regmap_write(lt8911exb->regmap, 0x1e, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x23, 0xf0); // 0x80
+
+ regmap_write(lt8911exb->regmap, 0x2b, 0x80); // 0xa0
+
+#ifdef _test_pattern_
+ regmap_write(lt8911exb->regmap, 0x26, (pcr_m | 0x80));
+#else
+
+ regmap_write(lt8911exb->regmap, 0x26, pcr_m);
+
+// regmap_write(lt8911exb->regmap, 0x27, Read_0xD095);
+// regmap_write(lt8911exb->regmap, 0x28, Read_0xD096);
+#endif
+
+ lt8911exb_mipi_video_timing(lt8911exb); //defualt setting is 1080P
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x81); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x03, 0x7b); //PCR reset
+ regmap_write(lt8911exb->regmap, 0x03, 0xff);
+
+#ifdef _eDP_2G7_
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x19, 0x31);
+ regmap_write(lt8911exb->regmap, 0x1a, 0x36); // sync m
+ regmap_write(lt8911exb->regmap, 0x1b, 0x00); // sync_k [7:0]
+ regmap_write(lt8911exb->regmap, 0x1c, 0x00); // sync_k [13:8]
+
+ // txpll Analog
+ regmap_write(lt8911exb->regmap, 0xff, 0x82);
+ regmap_write(lt8911exb->regmap, 0x09, 0x00); // div hardware mode, for ssc.
+
+// regmap_write(lt8911exb->regmap, 0x01, 0x18);// default : 0x18
+ regmap_write(lt8911exb->regmap, 0x02, 0x42);
+ regmap_write(lt8911exb->regmap, 0x03, 0x00); // txpll en = 0
+ regmap_write(lt8911exb->regmap, 0x03, 0x01); // txpll en = 1
+// regmap_write(lt8911exb->regmap, 0x04, 0x3a);// default : 0x3A
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x10); // cal en = 0
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfd);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x11); // cal en = 1
+
+ // ssc
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x13, 0x83);
+ regmap_write(lt8911exb->regmap, 0x14, 0x41);
+ regmap_write(lt8911exb->regmap, 0x16, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x18, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x19, 0x33);
+#endif
+
+#ifdef _eDP_1G62_
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x19, 0x31);
+ regmap_write(lt8911exb->regmap, 0x1a, 0x20); // sync m
+ regmap_write(lt8911exb->regmap, 0x1b, 0x19); // sync_k [7:0]
+ regmap_write(lt8911exb->regmap, 0x1c, 0x99); // sync_k [13:8]
+
+ // txpll Analog
+ regmap_write(lt8911exb->regmap, 0xff, 0x82);
+ regmap_write(lt8911exb->regmap, 0x09, 0x00); // div hardware mode, for ssc.
+ // regmap_write(lt8911exb->regmap, 0x01, 0x18);// default : 0x18
+ regmap_write(lt8911exb->regmap, 0x02, 0x42);
+ regmap_write(lt8911exb->regmap, 0x03, 0x00); // txpll en = 0
+ regmap_write(lt8911exb->regmap, 0x03, 0x01); // txpll en = 1
+ // regmap_write(lt8911exb->regmap, 0x04, 0x3a);// default : 0x3A
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x10); // cal en = 0
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfd);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x11); // cal en = 1
+
+ //ssc
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x13, 0x83);
+ regmap_write(lt8911exb->regmap, 0x14, 0x41);
+ regmap_write(lt8911exb->regmap, 0x16, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x18, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x19, 0x33);
+#endif
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+
+ for (i = 0; i < 5; i++) {//Check Tx PLL
+ mdelay(5);
+ regmap_read(lt8911exb->regmap, 0x37, &chip_read);
+ if (chip_read & 0x02) {
+ DRM_DEBUG("\r\n LT8911 tx pll locked");
+ break;
+ } else {
+ DRM_DEBUG("\r\n LT8911 tx pll unlocked");
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfd);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x87);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x10);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x11);
+ }
+ }
+
+ // AUX reset
+ regmap_write(lt8911exb->regmap, 0xff, 0x81); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x07, 0xfe);
+ regmap_write(lt8911exb->regmap, 0x07, 0xff);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfe);
+
+ /* tx phy */
+ regmap_write(lt8911exb->regmap, 0xff, 0x82); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x11, 0x00);
+ regmap_write(lt8911exb->regmap, 0x13, 0x10);
+ regmap_write(lt8911exb->regmap, 0x14, 0x0c);
+ regmap_write(lt8911exb->regmap, 0x14, 0x08);
+ regmap_write(lt8911exb->regmap, 0x13, 0x20);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x82); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x0e, 0x35);
+// regmap_write(lt8911exb->regmap, 0x12, 0xff);
+// regmap_write(lt8911exb->regmap, 0xff, 0x80);
+// regmap_write(lt8911exb->regmap, 0x40, 0x22);
+
+ /*eDP Tx Digital */
+ regmap_write(lt8911exb->regmap, 0xff, 0xa8); // Change Reg bank
+
+#ifdef _test_pattern_
+
+ regmap_write(lt8911exb->regmap, 0x24, 0x50); // bit2 ~ bit 0 : test panttern image mode
+ regmap_write(lt8911exb->regmap, 0x25, 0x70); // bit6 ~ bit 4 : test Pattern color
+ regmap_write(lt8911exb->regmap, 0x27, 0x50); //0x50:Pattern; 0x10:mipi video
+
+// regmap_write(lt8911exb->regmap, 0x2d, 0x00); // pure color setting
+// regmap_write(lt8911exb->regmap, 0x2d, 0x84); // black color
+ regmap_write(lt8911exb->regmap, 0x2d, 0x88); // block
+
+#else
+ regmap_write(lt8911exb->regmap, 0x27, 0x10); //0x50:Pattern; 0x10:mipi video
+#endif
+
+#ifdef _6bit_
+ regmap_write(lt8911exb->regmap, 0x17, 0x00);
+ regmap_write(lt8911exb->regmap, 0x18, 0x00);
+#else
+ // _8bit_
+ regmap_write(lt8911exb->regmap, 0x17, 0x10);
+ regmap_write(lt8911exb->regmap, 0x18, 0x20);
+#endif
+
+ /* nvid */
+ regmap_write(lt8911exb->regmap, 0xff, 0xa0); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x00, (u8)(Nvid_Val[_Nvid] / 256)); // 0x08
+ regmap_write(lt8911exb->regmap, 0x01, (u8)(Nvid_Val[_Nvid] % 256)); // 0x00
+}
+
+void lt8911exb_video_check(struct lt8911exb *lt8911exb)
+{
+ unsigned int reg;
+ unsigned int temp2;
+
+ /* mipi byte clk check*/
+ regmap_write(lt8911exb->regmap, 0xff, 0x85); // Change Reg bank
+ regmap_write(lt8911exb->regmap, 0x1d, 0x00); //FM select byte clk
+ regmap_write(lt8911exb->regmap, 0x40, 0xf7);
+ regmap_write(lt8911exb->regmap, 0x41, 0x30);
+
+ if (ScrambleMode) {
+ regmap_write(lt8911exb->regmap, 0xa1, 0x82 ); //eDP scramble mode;
+ } else {
+ regmap_write(lt8911exb->regmap, 0xa1, 0x02 ); // DP scramble mode;
+ }
+
+ //regmap_write(lt8911exb->regmap, 0x17, 0xf0 ); // 0xf0:Close scramble; 0xD0 : Open scramble
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x09, 0x7d);
+ regmap_write(lt8911exb->regmap, 0x09, 0xfd);
+ regmap_write(lt8911exb->regmap, 0xff, 0x85);
+ mdelay(200);
+
+ regmap_read(lt8911exb->regmap, 0x50, &temp2);
+ if (temp2 == 0x03) {
+ //reg = LT8911EXB_IIC_Read_byte( 0x4d );
+ //reg = reg * 256 + LT8911EXB_IIC_Read_byte( 0x4e );
+ //reg = reg * 256 + LT8911EXB_IIC_Read_byte( 0x4f );
+
+ regmap_read(lt8911exb->regmap, 0x4d, ®);
+ DRM_DEBUG_ATOMIC("1 0x4d = %d\n",reg);
+ regmap_read(lt8911exb->regmap, 0x4e, &temp2);
+ DRM_DEBUG_ATOMIC("1 0x4e = %d\n",temp2);
+ reg = reg * 256 + temp2;
+ DRM_DEBUG_ATOMIC("1-1 reg = %d\n",reg);
+ regmap_read(lt8911exb->regmap, 0x4f, &temp2);
+ DRM_DEBUG_ATOMIC("1-1 0x4f = %d\n",temp2);
+ reg = reg * 256 + temp2;
+ DRM_DEBUG_ATOMIC("1-2 reg = %d\n",reg);
+
+
+ DRM_DEBUG( "\r\nvideo check: mipi byteclk = %d ", reg ); // mipi byteclk = reg * 1000
+ DRM_DEBUG( "\r\nvideo check: mipi bitrate = %d ", reg * 8); // mipi byteclk = reg * 1000
+ DRM_DEBUG( "\r\nvideo check: mipi pclk = %d ", reg /3 * 4 * 1000); // mipi byteclk = reg * 1000
+ } else {
+ DRM_DEBUG( "\r\nvideo check: mipi clk unstable" );
+ }
+
+ /* mipi vtotal check*/
+ //reg = LT8911EXB_IIC_Read_byte( 0x76 );
+ //reg = reg * 256 + LT8911EXB_IIC_Read_byte( 0x77 );
+ regmap_read(lt8911exb->regmap, 0x76, ®);
+ DRM_DEBUG_ATOMIC("2 0x76 = %d\n",reg);
+ regmap_read(lt8911exb->regmap, 0x77, &temp2);
+ DRM_DEBUG_ATOMIC("2 0x77 = %d\n",temp2);
+ reg = reg * 256 + temp2;
+ DRM_DEBUG_ATOMIC("2-1 reg = %d\n",reg);
+
+ DRM_DEBUG( "\r\nvideo check: Vtotal = %d", reg);
+
+ /* mipi word count check*/
+ regmap_write(lt8911exb->regmap, 0xff, 0xd0);
+ //reg = LT8911EXB_IIC_Read_byte( 0x82 );
+ //reg = reg * 256 + LT8911EXB_IIC_Read_byte( 0x83 );
+ //reg = reg / 3;
+ regmap_read(lt8911exb->regmap, 0x82, ®);
+ DRM_DEBUG_ATOMIC("3 0x82 = %d\n",reg);
+ regmap_read(lt8911exb->regmap, 0x83, &temp2);
+ DRM_DEBUG_ATOMIC("3 0x83 = %d\n",reg);
+ reg = reg * 256 + temp2;
+ reg = reg / 3;
+ DRM_DEBUG_ATOMIC( "\r\n3-1 reg = %d ", reg );
+
+
+ DRM_DEBUG( "\r\nvideo check: Hact(word counter) = %d", reg);
+
+ /* mipi Vact check*/
+ //reg = LT8911EXB_IIC_Read_byte( 0x85 );
+ //reg = reg * 256 + LT8911EXB_IIC_Read_byte( 0x86 );
+ regmap_read(lt8911exb->regmap, 0x85, ®);
+ DRM_DEBUG_ATOMIC("4 0x85 = %d\n",reg);
+ regmap_read(lt8911exb->regmap, 0x86, &temp2);
+ DRM_DEBUG_ATOMIC("4 0x86 = %d\n",temp2);
+ reg = reg * 256 + temp2;
+ DRM_DEBUG_ATOMIC( "\r\n4-1 reg = %d ", reg );
+
+ DRM_DEBUG( "\r\nvideo check: Vact = %d", reg);
+
+}
+
+void DpcdWrite(struct lt8911exb *lt8911exb, u32 Address, u8 Data)
+{
+ /***************************
+ 注意大小端的问题!
+ 这里默认是大端模式
+
+ Pay attention to the Big-Endian and Little-Endian!
+ The default mode is Big-Endian here.
+
+ ****************************/
+ u8 AddressH = 0x0f & (Address >> 16);
+ u8 AddressM = 0xff & (Address >> 8);
+ u8 AddressL = 0xff & Address;
+
+ unsigned int reg;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6);
+ regmap_write(lt8911exb->regmap, 0x2b, (0x80 | AddressH)); //CMD
+ regmap_write(lt8911exb->regmap, 0x2b, AddressM); //addr[15:8]
+ regmap_write(lt8911exb->regmap, 0x2b, AddressL); //addr[7:0]
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00); //data lenth
+ regmap_write(lt8911exb->regmap, 0x2b, Data); //data
+ regmap_write(lt8911exb->regmap, 0x2c, 0x00); //start Aux
+
+ mdelay(20); //more than 10ms
+ regmap_read(lt8911exb->regmap, 0x25, ®);
+ if ((reg & 0x0f) == 0x0c) {
+ return;
+ }
+}
+
+unsigned int DpcdRead( struct lt8911exb *lt8911exb, u32 Address )
+{
+ /***************************
+ 注意大小端的问题!
+ 这里默认是大端模式
+
+ Pay attention to the Big-Endian and Little-Endian!
+ The default mode is Big-Endian here.
+
+ ****************************/
+
+ unsigned int DpcdValue = 0x00;
+ unsigned int AddressH = 0x0f & (Address >> 16);
+ unsigned int AddressM = 0xff & (Address >> 8);
+ unsigned int AddressL = 0xff & Address;
+ unsigned int reg;
+ unsigned int temp;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x20); //Soft Link train
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6);
+ regmap_write(lt8911exb->regmap, 0x2a, 0x01);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6);
+ regmap_write(lt8911exb->regmap, 0x2b, (0x90 | AddressH)); //CMD
+ regmap_write(lt8911exb->regmap, 0x2b, AddressM); //addr[15:8]
+ regmap_write(lt8911exb->regmap, 0x2b, AddressL); //addr[7:0]
+ regmap_write(lt8911exb->regmap, 0x2b, 0x00); //data lenth
+ regmap_write(lt8911exb->regmap, 0x2c, 0x00); //start Aux read edid
+
+ mdelay(50); //more than 10ms
+ regmap_read(lt8911exb->regmap, 0x25, ®);
+ if ((reg & 0x0f) == 0x0c) {
+ regmap_read(lt8911exb->regmap, 0x39, &temp);
+ if (temp == 0x22) {
+ //LT8911EXB_IIC_Read_byte( 0x2b );
+ //DpcdValue = LT8911EXB_IIC_Read_byte( 0x2b );
+ regmap_read(lt8911exb->regmap, 0x2b, &DpcdValue);
+ regmap_read(lt8911exb->regmap, 0x2b, &DpcdValue);
+ }
+ } else {
+ regmap_write(lt8911exb->regmap, 0xff, 0x81); // change bank
+ regmap_write(lt8911exb->regmap, 0x07, 0xfe);
+ regmap_write(lt8911exb->regmap, 0x07, 0xff);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfe);
+ }
+
+ return DpcdValue;
+}
+
+
+
+void lt8911exb_link_train(struct lt8911exb *lt8911exb)
+{
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x06, 0xdf); // rset VID TX
+ regmap_write(lt8911exb->regmap, 0x06, 0xff);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x85);
+
+ //regmap_write(lt8911exb->regmap, 0x17, 0xf0 ); // turn off scramble
+
+ if (ScrambleMode) {
+ regmap_write(lt8911exb->regmap, 0xa1, 0x82); // eDP scramble mode;
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x20); //Soft Link train
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6);
+ regmap_write(lt8911exb->regmap, 0x2a, 0x01);
+
+ DpcdWrite(lt8911exb, 0x010a, 0x01);
+ mdelay(10);
+ DpcdWrite(lt8911exb, 0x0102, 0x00);
+ mdelay(10);
+ DpcdWrite(lt8911exb, 0x010a, 0x01);
+
+ mdelay(200);
+ //*/
+ } else {
+ regmap_write(lt8911exb->regmap, 0xa1, 0x02); // DP scramble mode;
+ }
+ /* Aux setup */
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x60); //Soft Link train
+ regmap_write(lt8911exb->regmap, 0xff, 0xa6);
+ regmap_write(lt8911exb->regmap, 0x2a, 0x00);
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x81);
+ regmap_write(lt8911exb->regmap, 0x07, 0xfe);
+ regmap_write(lt8911exb->regmap, 0x07, 0xff);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfc);
+ regmap_write(lt8911exb->regmap, 0x0a, 0xfe);
+
+ /* link train */
+
+ regmap_write(lt8911exb->regmap, 0xff, 0x85);
+ regmap_write(lt8911exb->regmap, 0x1a, eDP_lane);
+
+#ifdef _link_train_enable_
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x64);
+ regmap_write(lt8911exb->regmap, 0x01, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x0c, 0x85);
+ regmap_write(lt8911exb->regmap, 0x0c, 0xc5);
+#else
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x00);
+ regmap_write(lt8911exb->regmap, 0x01, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x14, 0x80);
+ regmap_write(lt8911exb->regmap, 0x14, 0x81);
+ mdelay(50);
+ regmap_write(lt8911exb->regmap, 0x14, 0x84);
+ mdelay(50);
+ regmap_write(lt8911exb->regmap, 0x14, 0xc0);
+#endif
+}
+
+void lt8911exb_reset(struct lt8911exb *lt8911exb)
+{
+ if (!lt8911exb->reset_gpio) {
+ DRM_DEBUG_ATOMIC("no gpio, no reset\n");
+ return;
+ }
+
+ gpiod_direction_output(lt8911exb->reset_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt8911exb->reset_gpio, 0);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt8911exb->reset_gpio, 1);
+ usleep_range(100*1000, 150*1000); //150ms
+}
+
+void LT8911EX_TxSwingPreSet(struct lt8911exb *lt8911exb)
+{
+ regmap_write(lt8911exb->regmap, 0xFF, 0x82);
+ regmap_write(lt8911exb->regmap, 0x22, Swing_Setting1[Level]); //lane 0 tap0
+ regmap_write(lt8911exb->regmap, 0x23, Swing_Setting2[Level]);
+ regmap_write(lt8911exb->regmap, 0x24, 0x80); //lane 0 tap1
+ regmap_write(lt8911exb->regmap, 0x25, 0x00);
+
+#if ( eDP_lane == 2 )
+ regmap_write(lt8911exb->regmap, 0x26, Swing_Setting1[Level]); //lane 1 tap0
+ regmap_write(lt8911exb->regmap, 0x27, Swing_Setting2[Level]);
+ regmap_write(lt8911exb->regmap, 0x28, 0x80); //lane 1 tap1
+ regmap_write(lt8911exb->regmap, 0x29, 0x00);
+#endif
+}
+
+void LT8911EXB_LinkTrainResultCheck( struct lt8911exb *lt8911exb)
+{
+#ifdef _link_train_enable_
+ u8 i;
+ unsigned int val;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ for (i = 0; i < 10; i++) {
+ regmap_read(lt8911exb->regmap, 0x82, &val);
+ DRM_DEBUG("\r\n0x82: 0x%x", val);
+ if (val & 0x20) {
+ if ((val & 0x1f) == 0x1e) {
+#ifdef _uart_debug_
+ DRM_INFO("\r\nedp link train successed: 0x%x", val);
+#endif
+ return;
+ } else {
+#ifdef _uart_debug_
+ DRM_INFO("\r\nedp link train failed: 0x%x", val);
+#endif
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ regmap_write(lt8911exb->regmap, 0x00, 0x00);
+ regmap_write(lt8911exb->regmap, 0x01, 0x0a);
+ regmap_write(lt8911exb->regmap, 0x14, 0x80);
+ regmap_write(lt8911exb->regmap, 0x14, 0x81);
+ mdelay(50);
+ regmap_write(lt8911exb->regmap, 0x14, 0x84);
+ mdelay(50);
+ regmap_write(lt8911exb->regmap, 0x14, 0xc0);
+ }
+
+#ifdef _uart_debug_
+
+ regmap_read(lt8911exb->regmap, 0x83, &val);
+ //DRM_DEBUG_ATOMIC("\r\nLT8911_LinkTrainResultCheck: panel link rate: 0x%bx",val);
+ DRM_INFO( "\r\npanel link rate: 0x%x", val );
+ regmap_read(lt8911exb->regmap, 0x84, &val);
+ //DRM_DEBUG_ATOMIC("\r\nLT8911_LinkTrainResultCheck: panel link count: 0x%bx",val);
+ DRM_INFO( "\r\npanel link count:0x%x ", val);
+#endif
+ mdelay(100); // return;
+ } else {
+ //DRM_DEBUG_ATOMIC("\r\nLT8911_LinkTrainResultCheck: link trian on going...");
+ mdelay(100);
+ }
+ }
+#endif
+}
+
+
+void LT8911EX_link_train_result(struct lt8911exb *lt8911exb)
+{
+ u8 i;
+ unsigned int reg;
+ unsigned int temp;
+ regmap_write(lt8911exb->regmap, 0xff, 0xac);
+ for (i = 0; i < 10; i++) {
+ regmap_read(lt8911exb->regmap, 0x82, ®);
+ DRM_DEBUG( "\r\n0x82 = 0x%x", reg );
+ if (reg & 0x20) {
+ if((reg & 0x1f) == 0x1e) {
+ DRM_DEBUG("\r\nLink train success, 0x82 = 0x%x", reg);
+ } else {
+ DRM_DEBUG("\r\nLink train fail, 0x82 = 0x%x", reg);
+ }
+
+ regmap_read(lt8911exb->regmap, 0x83, &temp);
+ DRM_DEBUG("\r\npanel link rate: 0x%x", temp);
+ regmap_read(lt8911exb->regmap, 0x84, &temp);
+ DRM_DEBUG("\r\npanel link count: 0x%x", temp);
+ return;
+ } else {
+ DRM_DEBUG("\r\nlink trian on going...");
+ }
+ mdelay(100);
+ }
+}
+
+void PCR_Status(struct lt8911exb *lt8911exb) // for debug
+{
+#ifdef _uart_debug_
+ unsigned int reg;
+
+ regmap_write(lt8911exb->regmap, 0xff, 0xd0);
+ //reg = LT8911EXB_IIC_Read_byte( 0x87 );
+ regmap_read(lt8911exb->regmap, 0x87, ®);
+
+ DRM_INFO("\r\nReg0xD087 = ");
+ DRM_INFO(" 0x%x ", reg);
+ DRM_INFO("\r\n ");
+ if (reg & 0x10) {
+ DRM_INFO( "\r\nPCR Clock stable" );
+ } else {
+ DRM_INFO( "\r\nPCR Clock unstable" );
+ }
+ DRM_INFO("\r\n ");
+#endif
+}
+
+static int lt8911exb_chip_id(struct lt8911exb *lt8911exb)
+{
+ u8 retry = 0;
+ unsigned int chip_id_h = 0, chip_id_m = 0, chip_id_l = 0;
+ int ret = -EAGAIN;
+
+ while(retry++ < 3) {
+ ret = regmap_write(lt8911exb->regmap, 0xff, 0x81);
+
+ if(ret < 0) {
+ dev_err(lt8911exb->dev, "LT8911EXB i2c test write addr:0xff failed\n");
+ continue;
+ }
+
+ ret = regmap_write(lt8911exb->regmap, 0x08, 0x7f);
+
+ if(ret < 0) {
+ dev_err(lt8911exb->dev, "LT8911EXB i2c test write addr:0x08 failed\n");
+ continue;
+ }
+
+ regmap_read(lt8911exb->regmap, 0x00, &chip_id_l);
+ regmap_read(lt8911exb->regmap, 0x01, &chip_id_m);
+ regmap_read(lt8911exb->regmap, 0x02, &chip_id_h);
+ // LT8911EXB i2c test success chipid: 0xe0517
+ DRM_DEBUG("LT8911EXB i2c test success chipid: 0x%x%x%x\n", chip_id_h, chip_id_m, chip_id_l);
+
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int lt8911exb_panel_enable(struct drm_panel *panel)
+{
+ struct lt8911exb *lt8911exb = panel_to_lt8911exb(panel);
+
+ DRM_INFO("%s()\n", __func__);
+
+ schedule_delayed_work(<8911exb->init_work,
+ msecs_to_jiffies(500));
+ lt8911exb->init_work_pending = true;
+
+ return 0;
+}
+
+static int lt8911exb_panel_disable(struct drm_panel *panel)
+{
+ struct lt8911exb *lt8911exb = panel_to_lt8911exb(panel);
+
+ DRM_INFO("%s()\n", __func__);
+
+ gpiod_direction_output(lt8911exb->bl_gpio, 0);
+ if (!IS_ERR_OR_NULL(lt8911exb->enable_gpio)) {
+ gpiod_direction_output(lt8911exb->enable_gpio, 0);
+ }
+ usleep_range(50*1000, 100*1000); //100ms
+
+ gpiod_direction_output(lt8911exb->standby_gpio, 0);
+
+ if (lt8911exb->init_work_pending) {
+ cancel_delayed_work_sync(<8911exb->init_work);
+ lt8911exb->init_work_pending = false;
+ }
+
+ return 0;
+}
+
+static int lt8911exb_panel_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ unsigned int i, num = 0;
+ static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(lt8911exb_panel_modes); i++) {
+ const struct drm_display_mode *m = <8911exb_panel_modes[i];
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, m);
+ if (!mode) {
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay,
+ drm_mode_vrefresh(m));
+ continue;
+ }
+
+ mode->type |= DRM_MODE_TYPE_DRIVER;
+
+ if (i == 0)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ num++;
+ }
+
+ connector->display_info.bpc = 8;
+ // 1920x1080
+ #if MIPI_DSI_1920x1080
+ connector->display_info.width_mm = 309;
+ connector->display_info.height_mm = 174;
+ #endif
+
+ // 1920x1200
+ #if MIPI_DSI_1920x1200
+ connector->display_info.width_mm = 301;
+ connector->display_info.height_mm = 188;
+ #endif
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ return num;
+}
+
+
+static const struct drm_panel_funcs lt8911exb_panel_funcs = {
+ .disable = lt8911exb_panel_disable,
+ .enable = lt8911exb_panel_enable,
+ .get_modes = lt8911exb_panel_get_modes,
+};
+
+static void init_work_func(struct work_struct *work)
+{
+ struct lt8911exb *lt8911exb = container_of(work, struct lt8911exb,
+ init_work.work);
+
+ DRM_DEBUG(" %s() \n", __func__);
+
+ gpiod_direction_output(lt8911exb->standby_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+
+ lt8911exb_reset(lt8911exb);
+ lt8911exb_chip_id(lt8911exb);
+
+ lt8911exb_edp_video_cfg(lt8911exb);
+ lt8911exb_setup(lt8911exb);
+ LT8911EX_TxSwingPreSet(lt8911exb);
+
+ lt8911exb_read_edid(lt8911exb);
+
+ ScrambleMode = 0;
+ lt8911exb_link_train(lt8911exb);
+ LT8911EXB_LinkTrainResultCheck(lt8911exb);
+ LT8911EX_link_train_result(lt8911exb);
+ lt8911exb_video_check(lt8911exb); //just for Check MIPI Input
+
+ DRM_DEBUG("\r\nDpcdRead(0x0202) = 0x%x\r\n",DpcdRead(lt8911exb, 0x0202));
+
+ PCR_Status(lt8911exb);
+
+ if (!IS_ERR_OR_NULL(lt8911exb->enable_gpio)) {
+ gpiod_direction_output(lt8911exb->enable_gpio, 1);
+ }
+ gpiod_direction_output(lt8911exb->bl_gpio, 1);
+}
+static int lt8911exb_probe(struct i2c_client *client)
+{
+ struct lt8911exb *lt8911exb;
+ struct device *dev = &client->dev;
+ int ret;
+
+ struct device_node *endpoint, *dsi_host_node;
+ struct mipi_dsi_host *host;
+
+ struct device_node *lcd_node;
+ int rc;
+ const char *str;
+ char lcd_path[60];
+ const char *lcd_name;
+
+ struct mipi_dsi_device_info info = {
+ .type = IT8911_DSI_DRIVER_NAME,
+ .channel = 0,
+ .node = NULL,
+ };
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "Failed check I2C functionality");
+ return -ENODEV;
+ }
+
+ lt8911exb = devm_kzalloc(&client->dev, sizeof(*lt8911exb), GFP_KERNEL);
+ if (!lt8911exb)
+ return -ENOMEM;
+
+ lt8911exb->dev = &client->dev;
+ lt8911exb->client = client;
+
+ //regmap i2c , maybe useless
+ lt8911exb->regmap = devm_regmap_init_i2c(client, <8911exb_regmap_config);
+ if (IS_ERR(lt8911exb->regmap)) {
+ dev_err(lt8911exb->dev, "regmap i2c init failed\n");
+ return PTR_ERR(lt8911exb->regmap);
+ }
+
+ lt8911exb->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_IN);
+ if (IS_ERR_OR_NULL(lt8911exb->enable_gpio)) {
+ DRM_DEBUG("%s() failed get enable gpio\n", __func__);
+ // return PTR_ERR(lt8911exb->enable_gpio);
+ }
+
+ lt8911exb->standby_gpio = devm_gpiod_get_optional(dev, "standby",
+ GPIOD_IN);
+ if (IS_ERR(lt8911exb->standby_gpio)) {
+ dev_err(&client->dev, "Failed get standby gpio\n");
+ return PTR_ERR(lt8911exb->standby_gpio);
+ }
+
+ lt8911exb->bl_gpio = devm_gpiod_get_optional(dev, "bl",
+ GPIOD_IN);
+ if (IS_ERR(lt8911exb->bl_gpio)) {
+ dev_err(&client->dev, "Failed get bl gpio\n");
+ return PTR_ERR(lt8911exb->bl_gpio);
+ }
+ gpiod_direction_output(lt8911exb->bl_gpio, 0);
+ if (!IS_ERR_OR_NULL(lt8911exb->enable_gpio)) {
+ gpiod_direction_output(lt8911exb->enable_gpio, 0);
+ }
+ usleep_range(50*1000, 100*1000); //100ms
+
+ //disable firstly
+ gpiod_direction_output(lt8911exb->standby_gpio, 0);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt8911exb->standby_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+
+ lt8911exb->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_IN);
+ if (IS_ERR(lt8911exb->reset_gpio)) {
+ dev_err(&client->dev, "Failed get reset gpio\n");
+ return PTR_ERR(lt8911exb->reset_gpio);
+ }
+
+ lt8911exb_reset(lt8911exb);
+
+ i2c_set_clientdata(client, lt8911exb);
+
+ //check i2c communicate
+ ret = lt8911exb_chip_id(lt8911exb);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed communicate with IC use I2C\n");
+ return ret;
+ }
+
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!endpoint)
+ return -ENODEV;
+
+ dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+ if (!dsi_host_node)
+ goto error;
+
+ rc = of_property_read_string(dsi_host_node, "force-attached", &str);
+ if (!rc)
+ lcd_name = str;
+
+ sprintf(lcd_path, "/lcds/%s", lcd_name);
+ lcd_node = of_find_node_by_path(lcd_path);
+ if (!lcd_node) {
+ DRM_ERROR("%pOF: could not find %s node\n", dsi_host_node, lcd_name);
+ of_node_put(endpoint);
+ return -ENODEV;
+ }
+
+ DRM_INFO("%pOF: find %s node\n", dsi_host_node, lcd_name);
+
+ host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+ of_node_put(dsi_host_node);
+ if (!host) {
+ of_node_put(endpoint);
+ return -EPROBE_DEFER;
+ }
+
+ drm_panel_init(<8911exb->base, dev, <8911exb_panel_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+
+ /* This appears last, as it's what will unblock the DSI host
+ * driver's component bind function.
+ */
+ drm_panel_add(<8911exb->base);
+
+ lt8911exb->base.dev->of_node = lcd_node;
+ info.node = of_node_get(of_graph_get_remote_port(endpoint));
+ if (!info.node)
+ goto error;
+ of_node_put(endpoint);
+
+ lt8911exb->dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(lt8911exb->dsi)) {
+ dev_err(dev, "DSI device registration failed: %ld\n",
+ PTR_ERR(lt8911exb->dsi));
+ return PTR_ERR(lt8911exb->dsi);
+ }
+
+ INIT_DELAYED_WORK(<8911exb->init_work, init_work_func);
+
+ return 0;
+error:
+ of_node_put(endpoint);
+ return -ENODEV;
+}
+
+static void lt8911exb_remove(struct i2c_client *client)
+{
+ struct lt8911exb *lt8911exb = i2c_get_clientdata(client);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ mipi_dsi_detach(lt8911exb->dsi);
+
+ drm_panel_remove(<8911exb->base);
+
+ mipi_dsi_device_unregister(lt8911exb->dsi);
+}
+
+static struct i2c_device_id lt8911exb_id[] = {
+ { "lontium,lt8911exb", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, lt8911exb_id);
+
+static const struct of_device_id lt8911exb_match_table[] = {
+ { .compatible = "lontium,lt8911exb" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lt8911exb_match_table);
+
+static struct i2c_driver lt8911exb_driver = {
+ .driver = {
+ .name = "lt8911exb",
+ .of_match_table = lt8911exb_match_table,
+ },
+ .probe = lt8911exb_probe,
+ .remove = lt8911exb_remove,
+ .id_table = lt8911exb_id,
+};
+
+static int lt8911exb_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ dsi->lanes = 4;
+ dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_LPM);
+ dsi->format = MIPI_DSI_FMT_RGB888;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(&dsi->dev, "failed to attach dsi to host\n");
+ mipi_dsi_device_unregister(dsi);
+ }
+
+ return ret;
+}
+
+static const struct of_device_id spacemit_edp_of_match[] = {
+ { .compatible = "spacemit,edp-panel" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_edp_of_match);
+
+static struct mipi_dsi_driver lt8911exb_dsi_driver = {
+ .probe = lt8911exb_dsi_probe,
+ .driver = {
+ .name = IT8911_DSI_DRIVER_NAME,
+ .of_match_table = spacemit_edp_of_match,
+ },
+};
+
+
+static int __init init_lt8911exb(void)
+{
+ int err;
+
+ DRM_DEBUG("%s()\n", __func__);
+ mipi_dsi_driver_register(<8911exb_dsi_driver);
+ err = i2c_add_driver(<8911exb_driver);
+
+ return err;
+}
+
+module_init(init_lt8911exb);
+
+static void __exit exit_lt8911exb(void)
+{
+ DRM_DEBUG("%s()\n", __func__);
+ i2c_del_driver(<8911exb_driver);
+ mipi_dsi_driver_unregister(<8911exb_dsi_driver);
+}
+module_exit(exit_lt8911exb);
+
+MODULE_DESCRIPTION("LT8911EXB_MIPI to eDP Reg Setting driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/atomic.h>
+#include <linux/workqueue.h>
+#include <asm/unaligned.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_print.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_bridge.h>
+#include <linux/delay.h>
+#include <drm/display/drm_dp_aux_bus.h>
+#include <drm/display/drm_dp_helper.h>
+
+#include "spacemit_dsi.h"
+
+#define IT9711_DSI_DRIVER_NAME "spacemit-dp-drv"
+#define MIPI_DSI_1920x1080 1
+
+static const struct drm_display_mode lt9711_panel_modes[] = {
+
+#if MIPI_DSI_1920x1080
+ {
+ .clock = 142857143 / 1000,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 88,
+ .hsync_end = 1920 + 88 + 148,
+ .htotal = 1920 + 88 + 148 + 44,
+ .vdisplay = 1080,
+ .vsync_start = 1080 + 4,
+ .vsync_end = 1080 + 4 + 36,
+ .vtotal = 1080 + 4 + 36 + 5,
+ },
+#endif
+
+};
+
+struct lt9711 {
+ struct device *dev;
+ struct drm_bridge bridge;
+ struct drm_connector *connector;
+ struct spacemit_dsi_device *spacemit_dsi;
+
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio; //reset
+ struct gpio_desc *enable_gpio; //power
+
+ struct i2c_client *client;
+ struct drm_panel base;
+ struct mipi_dsi_device *dsi;
+
+ enum drm_connector_status status;
+ struct delayed_work detect_work;
+ bool detect_work_pending;
+};
+
+static const struct regmap_config lt9711_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+};
+
+static struct lt9711 *panel_to_lt9711(struct drm_panel *panel)
+{
+ return container_of(panel, struct lt9711, base);
+}
+
+static int lt9711_i2c_detect(struct lt9711 *lt9711)
+{
+ u8 retry = 0;
+ unsigned int status = 0;
+ int ret = -EAGAIN;
+
+ while(retry++ < 3) {
+
+ ret = regmap_write(lt9711->regmap, 0xff, 0x80);
+ if(ret < 0) {
+ dev_err(lt9711->dev, "LT9711 i2c detect write addr:0xff failed\n");
+ continue;
+ }
+
+ regmap_read(lt9711->regmap, 0xd6, &status);
+ // LT9711 i2c detect success status: 0xee
+ DRM_DEBUG("LT9711 i2c detect success status: 0x%x\n", status);
+
+ if (0xee == status)
+ lt9711->status = connector_status_connected;
+ else
+ lt9711->status = connector_status_disconnected;
+
+ break;
+ }
+
+ return ret;
+}
+
+static int lt9711_panel_enable(struct drm_panel *panel)
+{
+ // struct lt9711 *lt9711 = panel_to_lt9711(panel);
+ DRM_DEBUG(" %s() \n", __func__);
+
+ return 0;
+}
+
+static int lt9711_panel_disable(struct drm_panel *panel)
+{
+ // struct lt9711 *lt9711 = panel_to_lt9711(panel);
+ DRM_DEBUG(" %s() \n", __func__);
+
+ return 0;
+}
+
+static int lt9711_panel_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ // struct lt9711 *lt9711 = panel_to_lt9711(panel);
+ unsigned int i, num = 0;
+ static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ DRM_DEBUG(" %s() \n", __func__);
+
+ for (i = 0; i < ARRAY_SIZE(lt9711_panel_modes); i++) {
+ const struct drm_display_mode *m = <9711_panel_modes[i];
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev, m);
+ if (!mode) {
+ dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
+ m->hdisplay, m->vdisplay,
+ drm_mode_vrefresh(m));
+ continue;
+ }
+
+ mode->type |= DRM_MODE_TYPE_DRIVER;
+
+ if (i == 0)
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_set_name(mode);
+ drm_mode_probed_add(connector, mode);
+ num++;
+ }
+
+ connector->display_info.bpc = 8;
+ // 1920x1080
+ #if MIPI_DSI_1920x1080
+ connector->display_info.width_mm = 309;
+ connector->display_info.height_mm = 174;
+ #endif
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+ return num;
+}
+
+
+static const struct drm_panel_funcs lt9711_panel_funcs = {
+ .disable = lt9711_panel_disable,
+ .enable = lt9711_panel_enable,
+ .get_modes = lt9711_panel_get_modes,
+};
+
+static void detect_work_func(struct work_struct *work)
+{
+ struct lt9711 *lt9711 = container_of(work, struct lt9711,
+ detect_work.work);
+ int ret;
+
+ //check i2c communicate
+ ret = lt9711_i2c_detect(lt9711);
+ if (ret < 0) {
+ DRM_INFO("detect DP failed communicate with IC use I2C\n");
+ }
+
+ if (lt9711->spacemit_dsi) {
+ DRM_DEBUG(" %s() connector status %d\n", __func__, lt9711->spacemit_dsi->connector_status);
+ lt9711->spacemit_dsi->connector_status = lt9711->status;
+
+ if (lt9711->spacemit_dsi->previous_connector_status != lt9711->spacemit_dsi->connector_status) {
+ if (lt9711->connector) {
+ DRM_INFO(" %s() detect DP connector hpd event\n", __func__);
+ lt9711->spacemit_dsi->previous_connector_status = lt9711->spacemit_dsi->connector_status;
+ drm_helper_hpd_irq_event(lt9711->connector->dev);
+ }
+ }
+ }
+
+ schedule_delayed_work(<9711->detect_work,
+ msecs_to_jiffies(2000));
+}
+
+
+static int lt9711_probe(struct i2c_client *client)
+{
+ struct lt9711 *lt9711;
+ struct device *dev = &client->dev;
+ int ret;
+
+ struct device_node *endpoint, *dsi_host_node;
+ struct mipi_dsi_host *host;
+
+ struct device_node *lcd_node;
+ int rc;
+ const char *str;
+ char lcd_path[60];
+ const char *lcd_name;
+
+ struct mipi_dsi_device_info info = {
+ .type = IT9711_DSI_DRIVER_NAME,
+ .channel = 0,
+ .node = NULL,
+ };
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "Failed check I2C functionality");
+ return -ENODEV;
+ }
+
+ lt9711 = devm_kzalloc(&client->dev, sizeof(*lt9711), GFP_KERNEL);
+ if (!lt9711)
+ return -ENOMEM;
+
+ lt9711->dev = &client->dev;
+ lt9711->client = client;
+ lt9711->connector = NULL;
+ lt9711->spacemit_dsi = NULL;
+ lt9711->status = connector_status_disconnected;
+
+ //regmap i2c , maybe useless
+ lt9711->regmap = devm_regmap_init_i2c(client, <9711_regmap_config);
+ if (IS_ERR(lt9711->regmap)) {
+ dev_err(lt9711->dev, "regmap i2c init failed\n");
+ return PTR_ERR(lt9711->regmap);
+ }
+
+ lt9711->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_IN);
+ if (IS_ERR(lt9711->enable_gpio)) {
+ dev_err(lt9711->dev, "Failed get enable gpio\n");
+ return PTR_ERR(lt9711->enable_gpio);
+ }
+
+ lt9711->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_IN);
+ if (IS_ERR(lt9711->reset_gpio)) {
+ dev_err(lt9711->dev, "Failed get reset gpio\n");
+ return PTR_ERR(lt9711->reset_gpio);
+ }
+
+ //disable firstly
+ gpiod_direction_output(lt9711->enable_gpio, 0);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt9711->enable_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+
+ gpiod_direction_output(lt9711->reset_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt9711->reset_gpio, 0);
+ usleep_range(50*1000, 100*1000); //100ms
+ gpiod_direction_output(lt9711->reset_gpio, 1);
+ usleep_range(100*1000, 150*1000); //150ms
+
+ i2c_set_clientdata(client, lt9711);
+ dev_set_drvdata(dev, lt9711);
+
+ //check i2c communicate
+ ret = lt9711_i2c_detect(lt9711);
+ if (ret < 0) {
+ DRM_INFO("detect DP failed communicate with IC use I2C\n");
+ return ret;
+ }
+
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!endpoint)
+ return -ENODEV;
+
+ dsi_host_node = of_graph_get_remote_port_parent(endpoint);
+ if (!dsi_host_node)
+ goto error;
+
+ rc = of_property_read_string(dsi_host_node, "force-attached", &str);
+ if (!rc)
+ lcd_name = str;
+
+ sprintf(lcd_path, "/lcds/%s", lcd_name);
+ lcd_node = of_find_node_by_path(lcd_path);
+ if (!lcd_node) {
+ DRM_ERROR("%pOF: could not find %s node\n", dsi_host_node, lcd_name);
+ of_node_put(endpoint);
+ return -ENODEV;
+ }
+
+ DRM_INFO("%pOF: find %s node\n", dsi_host_node, lcd_name);
+
+ host = of_find_mipi_dsi_host_by_node(dsi_host_node);
+ of_node_put(dsi_host_node);
+ if (!host) {
+ of_node_put(endpoint);
+ return -EPROBE_DEFER;
+ }
+
+ drm_panel_init(<9711->base, dev, <9711_panel_funcs,
+ DRM_MODE_CONNECTOR_DisplayPort);
+
+ /* This appears last, as it's what will unblock the DSI host
+ * driver's component bind function.
+ */
+ drm_panel_add(<9711->base);
+
+ lt9711->base.dev->of_node = lcd_node;
+ info.node = of_node_get(of_graph_get_remote_port(endpoint));
+ if (!info.node)
+ goto error;
+ of_node_put(endpoint);
+
+ lt9711->dsi = mipi_dsi_device_register_full(host, &info);
+ if (IS_ERR(lt9711->dsi)) {
+ dev_err(dev, "DSI device registration failed: %ld\n",
+ PTR_ERR(lt9711->dsi));
+ return PTR_ERR(lt9711->dsi);
+ }
+
+ INIT_DELAYED_WORK(<9711->detect_work, detect_work_func);
+ schedule_delayed_work(<9711->detect_work,
+ msecs_to_jiffies(2000));
+ lt9711->detect_work_pending = true;
+
+ return 0;
+error:
+ of_node_put(endpoint);
+ return -ENODEV;
+}
+
+static void lt9711_remove(struct i2c_client *client)
+{
+ struct lt9711 *lt9711 = i2c_get_clientdata(client);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (lt9711->detect_work_pending) {
+ cancel_delayed_work_sync(<9711->detect_work);
+ lt9711->detect_work_pending = false;
+ }
+
+ lt9711->connector = NULL;
+ lt9711->spacemit_dsi = NULL;
+
+ mipi_dsi_detach(lt9711->dsi);
+ drm_panel_remove(<9711->base);
+ mipi_dsi_device_unregister(lt9711->dsi);
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int lt9711_drv_pm_suspend(struct device *dev)
+{
+ struct lt9711 *lt9711 = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (lt9711->detect_work_pending) {
+ cancel_delayed_work_sync(<9711->detect_work);
+ lt9711->detect_work_pending = false;
+ }
+
+ gpiod_direction_output(lt9711->enable_gpio, 0);
+ usleep_range(50*1000, 100*1000); //100ms
+
+ return 0;
+}
+
+static int lt9711_drv_pm_resume(struct device *dev)
+{
+ struct lt9711 *lt9711 = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ gpiod_direction_output(lt9711->enable_gpio, 1);
+ usleep_range(50*1000, 100*1000); //100ms
+
+ if (!lt9711->detect_work_pending) {
+ schedule_delayed_work(<9711->detect_work,
+ msecs_to_jiffies(2000));
+ lt9711->detect_work_pending = true;
+ }
+
+ return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops lt9711_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(lt9711_drv_pm_suspend,
+ lt9711_drv_pm_resume)
+};
+
+static struct i2c_device_id lt9711_id[] = {
+ { "lontium,lt9711", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, lt9711_id);
+
+static const struct of_device_id lt9711_match_table[] = {
+ { .compatible = "lontium,lt9711" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lt9711_match_table);
+
+static struct i2c_driver lt9711_driver = {
+ .driver = {
+ .name = "lt9711",
+ .of_match_table = lt9711_match_table,
+ .pm = <9711_pm_ops,
+ },
+ .probe = lt9711_probe,
+ .remove = lt9711_remove,
+ .id_table = lt9711_id,
+};
+
+static int lt9711_dsi_probe(struct mipi_dsi_device *dsi)
+{
+ int ret;
+ struct mipi_dsi_host *host;
+ struct drm_panel *panel;
+ struct spacemit_dsi *mipi_dsi;
+ struct lt9711 *lt9711;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ dsi->lanes = 4;
+ dsi->mode_flags = (MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
+ MIPI_DSI_MODE_LPM);
+ dsi->format = MIPI_DSI_FMT_RGB888;
+
+ ret = mipi_dsi_attach(dsi);
+ if (ret < 0) {
+ dev_err(&dsi->dev, "failed to attach dsi to host\n");
+ mipi_dsi_device_unregister(dsi);
+ } else {
+ host = dsi->host;
+ mipi_dsi = host_to_dsi(host);
+
+ panel = mipi_dsi->panel;
+ lt9711 = panel_to_lt9711(panel);
+
+ mipi_dsi->ctx.dsi_subconnector = SPACEMIT_DSI_SUBCONNECTOR_DP;
+ mipi_dsi->ctx.previous_connector_status = lt9711->status;
+ mipi_dsi->ctx.connector_status = mipi_dsi->ctx.previous_connector_status;
+
+ lt9711->connector = &mipi_dsi->connector;
+ lt9711->spacemit_dsi = &mipi_dsi->ctx;
+ }
+
+ return ret;
+}
+
+static const struct of_device_id spacemit_dp_of_match[] = {
+ { .compatible = "spacemit,dp-panel" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, spacemit_edp_of_match);
+
+static struct mipi_dsi_driver lt9711_dsi_driver = {
+ .probe = lt9711_dsi_probe,
+ .driver = {
+ .name = IT9711_DSI_DRIVER_NAME,
+ .of_match_table = spacemit_dp_of_match,
+ },
+};
+
+
+static int __init init_lt9711(void)
+{
+ int err;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ mipi_dsi_driver_register(<9711_dsi_driver);
+ err = i2c_add_driver(<9711_driver);
+
+ return err;
+}
+
+module_init(init_lt9711);
+
+static void __exit exit_lt9711(void)
+{
+ DRM_DEBUG("%s()\n", __func__);
+
+ i2c_del_driver(<9711_driver);
+ mipi_dsi_driver_unregister(<9711_dsi_driver);
+}
+module_exit(exit_lt9711);
+
+MODULE_DESCRIPTION("LT9711_MIPI to DP Reg Setting driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_address.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/mm.h>
+#include <linux/memblock.h>
+
+static bool spacemit_dpu_free_logo = false;
+
+int spacemit_dpu_free_bootloader_mem(struct reserved_mem *rmem)
+{
+ void __iomem *rmem_vaddr_start;
+ void __iomem *rmem_vaddr_end;
+
+ if (spacemit_dpu_free_logo)
+ return 0;
+
+ pr_info("Reserved memory: detected bootloader logo memory at %pa, size %ld MB\n",
+ &rmem->base, (unsigned long)rmem->size / SZ_1M);
+
+ rmem_vaddr_start = phys_to_virt(rmem->base);
+ rmem_vaddr_end = phys_to_virt(rmem->base + rmem->size - 1);
+
+ free_reserved_area(rmem_vaddr_start, rmem_vaddr_end, -1, "framebuffer");
+
+ spacemit_dpu_free_logo = true;
+
+ return 0;
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_BOOTLOADER_H_
+#define _SPACEMIT_BOOTLOADER_H_
+
+#include <linux/of_reserved_mem.h>
+
+int spacemit_dpu_free_bootloader_mem(struct reserved_mem *rmem);
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/sort.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "spacemit_cmdlist.h"
+#include "spacemit_dpu_reg.h"
+#include "spacemit_drm.h"
+#include "dpu/dpu_saturn.h"
+
+#define CL_HEADER_SZ sizeof(struct cmdlist_header)
+#define CL_ROW_SZ sizeof(struct cmdlist_row)
+
+static inline struct
+spacemit_plane_state *cl_to_spacemit_pstate(const struct cmdlist *cl)
+{
+ return container_of(cl, struct spacemit_plane_state, cl);
+}
+
+static void print_row(struct cmdlist_row *row) {
+ u32 * p = (u32 *) row;
+ DRM_DEBUG("print_row: 0x%02x, 0x%02x, 0x%02x, 0x%02x", *p, *(p+1), *(p+2), *(p+3));
+}
+
+static int cmdlist_reg_cmp(const void * r1, const void * r2) {
+ const struct cmdlist_reg *reg1 = (const struct cmdlist_reg *) r1;
+ const struct cmdlist_reg *reg2 = (const struct cmdlist_reg *) r2;
+ if (reg1->offset > reg2->offset)
+ return 1;
+ else if (reg1->offset < reg2->offset)
+ return -1;
+ else
+ return 0;
+}
+
+static void cmdlist_reg_swap(void * r1, void * r2, int size) {
+ struct cmdlist_reg *reg1 = (struct cmdlist_reg *) r1;
+ struct cmdlist_reg *reg2 = (struct cmdlist_reg *) r2;
+ struct cmdlist_reg tmp = *reg1;
+ *reg1 = *reg2;
+ *reg2 = tmp;
+}
+
+void cmdlist_regs_packing(struct drm_plane *plane) {
+ struct spacemit_dpu *dpu = crtc_to_dpu(plane->state->crtc);
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(plane->state);
+ struct cmdlist *cl = &spacemit_pstate->cl;
+ struct cmdlist_row *row;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct cmdlist_reg *regs = priv->cmdlist_regs;
+ int i;
+
+ cl->size = PER_CMDLIST_SIZE;
+ cl->va = dma_alloc_coherent(dpu->dev, cl->size, &cl->pa, GFP_KERNEL | __GFP_ZERO);
+ if (cl->va == NULL) {
+ DRM_ERROR("Failed to allocate %d bytes for dpu plane%d cmdlist buffer\n",
+ PER_CMDLIST_SIZE, plane->state->zpos);
+ return;
+ }
+
+ sort(regs, priv->cmdlist_num, sizeof(struct cmdlist_reg), cmdlist_reg_cmp, cmdlist_reg_swap);
+ for (i = 0; i < priv->cmdlist_num; i++) {
+ DRM_DEBUG("cmdlist_reg, regs[%d] = {0x%02x, 0x%02x}", i, regs[i].offset, regs[i].value);
+ }
+
+ DRM_DEBUG("-----cmdlist_regs_packing----- priv->cmdlist_num = %u, rch_id = %d, ch_y = %u\n",
+ priv->cmdlist_num, spacemit_pstate->rdma_id, spacemit_pstate->state.crtc_y);
+
+ row = (struct cmdlist_row *)((char *)cl->va + CL_HEADER_SZ);
+ for (i = 0; i < priv->cmdlist_num;) {
+ row->module_cfg_addr = regs[i].offset >> 2;
+ row->module_regs[0] = regs[i].value;
+ row->module_cfg_num = 1;
+ row->module_cfg_strobe = 0xf;
+ if (i + 1 < priv->cmdlist_num) {
+ if (regs[i + 1].offset - regs[i].offset == sizeof(u32)) {
+ row->module_regs[1] = regs[i + 1].value;
+ row->module_cfg_num = 2;
+ row->module_cfg_strobe = 0xff;
+ }
+ }
+ if (i + 2 < priv->cmdlist_num) {
+ if (regs[i + 2].offset - regs[i].offset == sizeof(u32) * 2) {
+ row->module_regs[2] = regs[i + 2].value;
+ row->module_cfg_num = 3;
+ row->module_cfg_strobe = 0xfff;
+ }
+ }
+
+ print_row(row);
+
+ i += row->module_cfg_num;
+ cl->nod_len++;
+ row = (struct cmdlist_row *)((char *)row + CL_ROW_SZ);
+ }
+ priv->cmdlist_num = 0; //clear cmdlist_regs buffer
+ DRM_DEBUG("-----cmdlist_regs_packing----- row_num = %d\n", row->module_cfg_num);
+}
+
+static inline void fill_top_row(struct cmdlist *cl) {
+ struct cmdlist_header *header;
+ struct cmdlist_row *row;
+ unsigned int cl_addr_h = 0;
+ struct spacemit_plane_state *spacemit_pstate = cl_to_spacemit_pstate(cl);
+ u8 rch_id = spacemit_pstate->rdma_id;
+ u8 scl_id = spacemit_pstate->scaler_id;
+ bool use_scl = spacemit_pstate->use_scl;
+ unsigned int zpos = spacemit_pstate->state.zpos;
+ u32 size = 0;
+
+ // fill header
+ header = (struct cmdlist_header *)(cl->va);
+ if (cl->next) {
+ header->next_list_addr = cl->next->pa;
+ } else
+ header->list_tag = 1;
+ // end cl->nod_len = cl->nod_len + 4, 3(row) + 1(head)
+ header->nod_len = cl->nod_len + 4;
+
+ // fill scaler row;
+ row = (struct cmdlist_row *)((char *)header + CL_HEADER_SZ + cl->nod_len * CL_ROW_SZ);
+ row->module_cfg_addr = ((DPU_CTRL_BASE_ADDR + DPU_NUM_REUSE_SCL) >> 2) + scl_id;
+ row->module_cfg_strobe = 0xff;
+ if (scl_id != SCALER_INVALID_ID) {
+ row->module_cfg_num = 1;
+ if (use_scl)
+ row->module_regs[0] = 1;
+ else
+ row->module_regs[0] = 0;
+ } else
+ row->module_cfg_num = 0;
+
+ // fill ch_y row
+ row = (struct cmdlist_row *)((char *)row + CL_ROW_SZ);
+ cl_addr_h = header->next_list_addr >> 32;
+ row->module_cfg_addr = (CMDLIST_BASE_ADDR + CMDLIST_CH_Y + rch_id * 4) >> 2;
+ row->module_cfg_num = cl->next ? 1 : 0;
+ row->module_cfg_strobe = 0xf;
+ row->module_regs[0] = cl->next ? cl_to_spacemit_pstate(cl->next)->state.crtc_y << 8 | \
+ (cl_addr_h & CMDLIST_ADDRH_MASK) : 0;
+ row->module_regs[1] = 0;
+
+ // fill last_row
+ row = (struct cmdlist_row *)((char *)row + CL_ROW_SZ);
+ row->module_cfg_addr = (DPU_CTRL_BASE_ADDR + CMDLIST_CFG_READY) >> 2;
+ row->module_cfg_num = 1;
+ row->module_cfg_strobe = 0xf0f;
+ row->row_eof_tag = 3;
+ row->module_regs[0] = 1 << rch_id;
+ row->module_regs[2] = rch_id;
+
+ size = (unsigned long)((char *)row + CL_ROW_SZ) - (unsigned long)header;
+ if (size > PER_CMDLIST_SIZE)
+ DRM_ERROR("plane%d cmdlist occupies %d bytes!\n", zpos, size);
+}
+
+void cmdlist_sort_by_group(struct drm_crtc *crtc) {
+ struct cmdlist * cur_cl;
+ struct cmdlist * p;
+ struct cmdlist * prev;
+ struct drm_plane *plane;
+ struct spacemit_dpu_rdma *rdmas = to_spacemit_crtc_state(crtc->state)->rdmas;
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+
+ drm_atomic_crtc_for_each_plane(plane, crtc) {
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(plane->state);
+ u32 rdma_id = spacemit_pstate->rdma_id;
+ cur_cl = (struct cmdlist *)(&(spacemit_pstate->cl));
+
+ if (!cur_cl->va)
+ continue;
+
+ rdmas[rdma_id].in_use = true;
+ if (priv->cmdlist_groups[rdma_id]) {
+ p = priv->cmdlist_groups[rdma_id];
+ prev = NULL;
+ while(p) {
+ if (cl_to_spacemit_pstate(p)->state.crtc_y < spacemit_pstate->state.crtc_y) {
+ prev = p;
+ p = p->next;
+ }
+ else
+ break;
+ }
+ if (!prev) {
+ priv->cmdlist_groups[rdma_id] = cur_cl;
+ cur_cl->next = p;
+ } else {
+ prev->next = cur_cl;
+ cur_cl->next = p;
+ }
+ } else {
+ priv->cmdlist_groups[rdma_id] = cur_cl;
+ cur_cl->next = NULL;
+ }
+ }
+}
+
+void cmdlist_atomic_commit(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state) {
+ int i;
+ struct cmdlist *cur_cl, *first_cl;
+ u32 val;
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ struct spacemit_dpu_rdma *cur_rdmas = to_spacemit_crtc_state(crtc->state)->rdmas;
+ struct spacemit_dpu_rdma *old_rdmas = to_spacemit_crtc_state(old_state)->rdmas;
+
+ for (i = 0; i < hwdev->rdma_nums; i++) {
+ /* Shut down the rdma used in previous frame first */
+ if (old_rdmas[i].in_use) {
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR,
+ dpu_ctl_reg_69[i].ctl_nml_cmdlist_rch_en, 0);
+ dpu_write_reg(hwdev, CMDLIST_REG, CMDLIST_BASE_ADDR, value32[i], 0);
+ }
+
+ if (cur_rdmas[i].in_use) {
+ DRM_DEBUG("+++++cmdlist_atomic_commit+++++ cmdlist group = %d\n", i);
+ cur_cl = priv->cmdlist_groups[i];
+ first_cl = cur_cl;
+ while(cur_cl) {
+ fill_top_row(cur_cl);
+ cur_cl = cur_cl->next;
+ }
+ val = cl_to_spacemit_pstate(first_cl)->state.crtc_y;
+ dpu_write_reg(hwdev, CMDLIST_REG, CMDLIST_BASE_ADDR, cmdlist_reg_14[i].cmdlist_ch_y, val);
+ val = ((priv->cmdlist_groups[i]->pa) & CMDLIST_ADDRL_ALIGN_MASK) >> CMDLIST_ADDRL_ALIGN_BITS;
+ dpu_write_reg(hwdev, CMDLIST_REG, CMDLIST_BASE_ADDR, cmdlist_reg_0[i].cmdlist_ch_start_addrl, val);
+#if defined (CONFIG_ARM64) || defined (CONFIG_ARM_LPAE)
+ val = (priv->cmdlist_groups[i]->pa) >> 32;
+ dpu_write_reg(hwdev, CMDLIST_REG, CMDLIST_BASE_ADDR, cmdlist_reg_14[i].cmdlist_ch_start_addrh, val);
+#else
+ dpu_write_reg(hwdev, CMDLIST_REG, CMDLIST_BASE_ADDR, cmdlist_reg_14[i].cmdlist_ch_start_addrh, 0);
+#endif
+ dpu_write_reg(hwdev, DPU_CTL_REG, DPU_CTRL_BASE_ADDR,
+ dpu_ctl_reg_69[i].ctl_nml_cmdlist_rch_en, 1);
+ priv->cmdlist_groups[i] = NULL;
+ }
+ }
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SATURN_FW_CMDLIST_H_
+#define _SATURN_FW_CMDLIST_H_
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_plane.h>
+
+#define PER_CMDLIST_SIZE 4096
+#define CMDLIST_CH_Y 0x38
+#define DPU_NUM_REUSE_SCL 0xF4
+#define CMDLIST_CFG_READY 0x14C
+
+#define CMDLIST_ADDRH_MASK (0x3)
+
+#define CMDLIST_REGS_NUM (PAGE_SIZE / sizeof(struct cmdlist_reg))
+
+struct cmdlist {
+ u16 nod_len; //the number of cmdlist row.
+ u32 size;
+ void *va;
+ dma_addr_t pa;
+ struct cmdlist * next;
+};
+
+/* cmdlist structure */
+struct cmdlist_header {
+ u64 next_list_addr : 34; //the next cmdlist address
+ // reserved
+ u32 :6;
+ u32 nod_len : 16;
+ // if the cmdlist is last one tag = 1, otherwish tag = 0
+ u32 list_tag : 1;
+ // reserved
+ u32 : 7;
+ u64 : 64;
+};
+
+struct cmdlist_row {
+ u32 module_cfg_addr : 16;
+ //the last row must 1-2, otherwise 1-3.
+ u32 module_cfg_num : 2;
+ u32 module_cfg_strobe : 12;
+ //the last row tag = 3, otherwise tag = 0.
+ u32 row_eof_tag : 2;
+ u32 module_regs[3];
+};
+
+struct cmdlist_reg {
+ uint32_t offset;
+ uint32_t value;
+};
+
+#define dpu_offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->v.MEMBER)
+#define write_to_cmdlist(priv, module_name, module_base, reg, val) \
+{ \
+ u32 offset = module_base + dpu_offsetof(module_name, reg); \
+ priv->cmdlist_regs[priv->cmdlist_num].value = val; \
+ priv->cmdlist_regs[priv->cmdlist_num++].offset = offset; \
+}
+
+void cmdlist_regs_packing(struct drm_plane *plane);
+void cmdlist_sort_by_group(struct drm_crtc *crtc);
+void cmdlist_atomic_commit(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state);
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include "linux/compiler.h"
+#include <linux/stddef.h>
+#include <linux/gfp.h>
+#include <linux/dma-mapping.h>
+#include <drm/drm_framebuffer.h>
+
+#include "spacemit_cmdlist.h"
+#include "spacemit_dmmu.h"
+#include "spacemit_gem.h"
+#include "spacemit_drm.h"
+#include "spacemit_dpu.h"
+#include "spacemit_dpu_reg.h"
+
+static inline void spacemit_dmmu_fill_pgtable(uint32_t *ttbr, struct sg_table *sgt)
+{
+ struct sg_dma_page_iter dma_iter;
+ uint32_t i = 0, temp = 0;
+
+ for_each_sgtable_dma_page(sgt, &dma_iter, 0)
+ *ttbr++ = (sg_page_iter_dma_address(&dma_iter) >> PAGE_SHIFT) & 0x3FFFFF;
+ /*
+ * Due to slicon's alignment access requirement, fill more mmu entries
+ * to avoid ddrc filter error. We simply use the last valid ttbr value.
+ */
+ temp = *(ttbr - 1);
+ for (i = 0; i < HW_ALIGN_TTB_NUM; i++)
+ *ttbr++ = temp;
+}
+
+int spacemit_dmmu_map(struct drm_framebuffer *fb, struct dpu_mmu_tbl *mmu_tbl, u8 tbu_id, bool wb)
+{
+ struct spacemit_drm_private *priv = fb->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ const struct drm_format_info *format = NULL;
+ struct sg_table *sgt = NULL;
+ uint32_t total_size, offset1, offset2;
+ struct tbu_instance tbu = {0x0};
+ u8 fbc_mode, plane_num, rdma_id;
+ u32 val;
+
+ rdma_id = tbu_id / 2;
+
+ format = fb->format;
+ sgt = to_spacemit_obj(fb->obj[0])->sgt;
+
+ if (!wb && priv->contig_mem) {
+ phys_addr_t contig_pa = sg_dma_address(sgt->sgl);
+
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, TBU[tbu_id].TBU_Ctrl, 0x0);
+#if defined (CONFIG_ARM64) || defined (CONFIG_ARM_LPAE)
+ CONFIG_RDMA_ADDR_REG(priv, 0, rdma_id, contig_pa);
+ CONFIG_RDMA_ADDR_REG(priv, 1, rdma_id, (contig_pa + fb->offsets[1]));
+ CONFIG_RDMA_ADDR_REG(priv, 2, rdma_id, (contig_pa + fb->offsets[2]));
+#else
+ CONFIG_RDMA_ADDR_REG_32(priv, 0, rdma_id, contig_pa);
+ CONFIG_RDMA_ADDR_REG_32(priv, 1, rdma_id, (contig_pa + fb->offsets[1]));
+ CONFIG_RDMA_ADDR_REG_32(priv, 2, rdma_id, (contig_pa + fb->offsets[2]));
+#endif
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_RDMA_STRIDE0, (fb->pitches[1] << 16) | fb->pitches[0]);
+
+ return 0;
+ }
+
+ plane_num = format->num_planes;
+ fbc_mode = (fb->modifier > 0);
+ total_size = roundup(fb->obj[0]->size, PAGE_SIZE);
+ offset1 = plane_num > 1 ? fb->offsets[1] : total_size;
+ offset2 = plane_num > 2 ? fb->offsets[2] : total_size;
+
+ switch (plane_num) {
+ case 3:
+ tbu.ttb_pa[2] = mmu_tbl->pa + (offset2 >> PAGE_SHIFT) * 4;
+ tbu.tbu_va[2] = TBU_BASE_VA(tbu_id) + offset2;
+ tbu.ttb_size[2] = PAGE_ALIGN(total_size - rounddown(offset2, PAGE_SIZE)) >> PAGE_SHIFT;
+ fallthrough;
+ case 2:
+ tbu.ttb_pa[1] = mmu_tbl->pa + (offset1 >> PAGE_SHIFT) * 4;
+ tbu.tbu_va[1] = TBU_BASE_VA(tbu_id) + offset1;
+ tbu.ttb_size[1] = PAGE_ALIGN(offset2 - rounddown(offset1, PAGE_SIZE)) >> PAGE_SHIFT;
+ fallthrough;
+ case 1:
+ tbu.ttb_pa[0] = mmu_tbl->pa;
+ tbu.tbu_va[0] = TBU_BASE_VA(tbu_id);
+ tbu.ttb_size[0] = PAGE_ALIGN(offset1) >> PAGE_SHIFT;
+ fallthrough;
+ default:
+ break;
+ }
+ /* Special handling for afbc */
+ if (fbc_mode) {
+ tbu.tbu_va[1] = tbu.tbu_va[0];
+ tbu.ttb_pa[1] = tbu.ttb_pa[0];
+ tbu.ttb_size[1] = tbu.ttb_size[0];
+ }
+
+ spacemit_dmmu_fill_pgtable((uint32_t *)(mmu_tbl->va), sgt);
+
+ val = 0x1 | (fbc_mode << 1) | ((fbc_mode ? 1 : plane_num - 1) << 2);
+ /* Config hw regs */
+ if (wb) {
+ val = val | (DPU_QOS_LOW << 8);
+ CONFIG_WB_ADDR_REG(hwdev, 0, tbu.tbu_va[0]);
+ CONFIG_WB_ADDR_REG(hwdev, 1, tbu.tbu_va[1]);
+ dpu_write_reg(hwdev, WB_TOP_REG, WB0_TOP_BASE_ADDR, \
+ wb_wdma_stride, (fb->pitches[1] << 16) | fb->pitches[0]);
+ CONFIG_TBU_REGS(priv, hwdev, 0, tbu_id);
+ CONFIG_TBU_REGS(priv, hwdev, 1, tbu_id);
+ CONFIG_TBU_REGS(priv, hwdev, 2, tbu_id);
+ dpu_write_reg(hwdev, MMU_REG, MMU_BASE_ADDR, v.TBU[tbu_id].TBU_Ctrl, val);
+ } else {
+ val = val | (DPU_QOS_URGENT << 8);
+#if defined (CONFIG_ARM64) || defined (CONFIG_ARM_LPAE)
+ CONFIG_RDMA_ADDR_REG(priv, 0, rdma_id, tbu.tbu_va[0]);
+ CONFIG_RDMA_ADDR_REG(priv, 1, rdma_id, tbu.tbu_va[1]);
+ CONFIG_RDMA_ADDR_REG(priv, 2, rdma_id, tbu.tbu_va[2]);
+#else
+ CONFIG_RDMA_ADDR_REG_32(priv, 0, rdma_id, tbu.tbu_va[0]);
+ CONFIG_RDMA_ADDR_REG_32(priv, 1, rdma_id, tbu.tbu_va[1]);
+ CONFIG_RDMA_ADDR_REG_32(priv, 2, rdma_id, tbu.tbu_va[2]);
+#endif
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_RDMA_STRIDE0, (fb->pitches[1] << 16) | fb->pitches[0]);
+ CONFIG_TBU_REGS(priv, NULL, 0, tbu_id);
+ CONFIG_TBU_REGS(priv, NULL, 1, tbu_id);
+ CONFIG_TBU_REGS(priv, NULL, 2, tbu_id);
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, TBU[tbu_id].TBU_Ctrl, val);
+ }
+
+ return 0;
+}
+
+void spacemit_dmmu_unmap(struct drm_plane *plane)
+{
+ return;
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DMMU_H_
+#define _SPACEMIT_DMMU_H_
+
+#include <linux/types.h>
+
+#include <drm/drm_file.h>
+#include "dpu/dpu_saturn.h"
+
+#define DPU_QOS_URGENT 4
+#define DPU_QOS_NORMAL 3
+#define DPU_QOS_LOW 2
+/*
+ * In worst case, the tlb alignment requires src_x * 16 * pixel_bytes.
+ * The maximum src_x currently support is 4096. So we need to fill
+ * extra 60 (4096*15*4) entries into mmu page table.
+ */
+#define HW_ALIGN_TTB_NUM 60
+
+#define RD_OUTS_NUM 16
+#define RDMA_TIMELIMIT 0xFFFF
+
+#define BASE_VA 0x10000000ULL
+#define VA_STEP_PER_TBU 0x40000000ULL
+
+#define TBU_BASE_VA(tbu_id) ((uint64_t)BASE_VA + (uint64_t)VA_STEP_PER_TBU * tbu_id)
+
+#define CONFIG_TBU_REGS(priv, hwdev, reg_id, tbu_id) \
+{\
+ struct spacemit_hw_device *hwdev_p = (struct spacemit_hw_device *)hwdev; \
+ if (hwdev_p) { \
+ dpu_write_reg(hwdev_p, MMU_REG, MMU_BASE_ADDR, v.TBU[tbu_id].TBU_Base_Addr##reg_id##_Low, \
+ tbu.ttb_pa[reg_id] & 0xFFFFFFFF); \
+ dpu_write_reg(hwdev_p, MMU_REG, MMU_BASE_ADDR, v.TBU[tbu_id].TBU_Base_Addr##reg_id##_High, \
+ (tbu.ttb_pa[reg_id] >> 32) & 0x3); \
+ dpu_write_reg(hwdev_p, MMU_REG, MMU_BASE_ADDR, v.TBU[tbu_id].TBU_VA##reg_id, \
+ (tbu.tbu_va[reg_id] >> 12) & 0x3FFFFF); \
+ dpu_write_reg(hwdev_p, MMU_REG, MMU_BASE_ADDR, \
+ v.TBU[tbu_id].TBU_SIZE##reg_id, tbu.ttb_size[reg_id]); \
+ } else { \
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, \
+ TBU[tbu_id].TBU_Base_Addr##reg_id##_Low, \
+ tbu.ttb_pa[reg_id] & 0xFFFFFFFF); \
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, \
+ TBU[tbu_id].TBU_Base_Addr##reg_id## _High, \
+ (tbu.ttb_pa[reg_id] >> 32) & 0x3); \
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, TBU[tbu_id].TBU_VA##reg_id, \
+ (tbu.tbu_va[reg_id] >> 12) & 0x3FFFFF); \
+ write_to_cmdlist(priv, MMU_REG, MMU_BASE_ADDR, \
+ TBU[tbu_id].TBU_SIZE##reg_id, tbu.ttb_size[reg_id]); \
+ } \
+}
+
+#define CONFIG_RDMA_ADDR_REG(priv, reg_id, rdma_id, addr) \
+{ \
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_BASE_ADDR##reg_id##_LOW, addr & 0xFFFFFFFF); \
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_BASE_ADDR##reg_id##_HIGH, (addr >> 32) & 0x3); \
+}
+
+#define CONFIG_RDMA_ADDR_REG_32(priv, reg_id, rdma_id, addr) \
+{ \
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_BASE_ADDR##reg_id##_LOW, addr & 0xFFFFFFFF); \
+ write_to_cmdlist(priv, RDMA_PATH_X_REG, RDMA_BASE_ADDR(rdma_id), \
+ LEFT_BASE_ADDR##reg_id##_HIGH, 0); \
+}
+
+#define CONFIG_WB_ADDR_REG(hwdev, reg_id, addr) \
+{ \
+ struct spacemit_hw_device *hwdev_p = (struct spacemit_hw_device *)hwdev; \
+ dpu_write_reg(hwdev_p, WB_TOP_REG, WB0_TOP_BASE_ADDR, \
+ wb_wdma_base_addr##reg_id##_low, addr & 0xFFFFFFFF); \
+ dpu_write_reg(hwdev_p, WB_TOP_REG, WB0_TOP_BASE_ADDR, \
+ wb_wdma_base_addr##reg_id##_high, (addr >> 32) & 0x3); \
+}
+
+struct tbu_instance {
+ uint64_t ttb_pa[3];
+ uint64_t tbu_va[3];
+ uint32_t ttb_size[3];
+};
+
+int spacemit_dmmu_map(struct drm_framebuffer *fb, struct dpu_mmu_tbl *mmu_tbl, u8 tbu_id, bool wb);
+void spacemit_dmmu_unmap(struct drm_plane *plane);
+
+#endif /* _SPACEMIT_DMMU_H_ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "spacemit_dphy.h"
+#include "sysfs/sysfs_display.h"
+
+LIST_HEAD(dphy_core_head);
+
+int spacemit_dphy_resume(struct spacemit_dphy *dphy)
+{
+ if (dphy->core && dphy->core->init)
+ dphy->core->init(&dphy->ctx);
+
+ DRM_DEBUG("dphy resume OK\n");
+ return 0;
+}
+
+int spacemit_dphy_suspend(struct spacemit_dphy *dphy)
+{
+ if (dphy->core && dphy->core->uninit)
+ dphy->core->uninit(&dphy->ctx);
+
+ DRM_DEBUG("dphy suspend OK\n");
+ return 0;
+}
+
+int spacemit_dphy_reset(struct spacemit_dphy *dphy)
+{
+ if (dphy->core && dphy->core->reset)
+ dphy->core->reset(&dphy->ctx);
+
+ DRM_DEBUG("dphy reset OK\n");
+ return 0;
+}
+
+int spacemit_dphy_get_status(struct spacemit_dphy *dphy)
+{
+ if (dphy->core && dphy->core->get_status)
+ dphy->core->get_status(&dphy->ctx);
+
+ DRM_DEBUG("dphy get status OK\n");
+ return 0;
+}
+
+static int spacemit_dphy_device_create(struct spacemit_dphy *dphy,
+ struct device *parent)
+{
+ int ret;
+
+ dphy->dev.class = display_class;
+ dphy->dev.parent = parent;
+ dphy->dev.of_node = parent->of_node;
+ dev_set_name(&dphy->dev, "dphy%d", dphy->ctx.id);
+ dev_set_drvdata(&dphy->dev, dphy);
+
+ ret = device_register(&dphy->dev);
+ if (ret)
+ DRM_ERROR("dphy device register failed\n");
+
+ return ret;
+}
+
+static int spacemit_dphy_context_init(struct spacemit_dphy *dphy,
+ struct device_node *np)
+{
+ struct resource r;
+ u32 tmp;
+
+ if (dphy->core && dphy->core->parse_dt)
+ dphy->core->parse_dt(&dphy->ctx, np);
+
+ if (!of_address_to_resource(np, 0, &r)) {
+ dphy->ctx.base_addr = (void __iomem *)ioremap(r.start, resource_size(&r));
+ if (NULL == dphy->ctx.base_addr) {
+ DRM_ERROR("dphy ctrlbase ioremap failed\n");
+ return -EFAULT;
+ }
+ } else {
+ DRM_ERROR("parse dphy ctrl reg base failed\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(np, "dev-id", &tmp))
+ dphy->ctx.id = tmp;
+
+ return 0;
+}
+
+static int spacemit_dphy_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spacemit_dphy *dphy;
+ const char *str;
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
+ if (!dphy)
+ return -ENOMEM;
+
+ if (!of_property_read_string(np, "ip", &str))
+ dphy->core = dphy_core_ops_attach(str);
+ else
+ DRM_WARN("dphy pll ops parse failed\n");
+
+ ret = spacemit_dphy_context_init(dphy, pdev->dev.of_node);
+ if (ret)
+ return ret;
+
+ spacemit_dphy_device_create(dphy, &pdev->dev);
+ spacemit_dphy_sysfs_init(&dphy->dev);
+ platform_set_drvdata(pdev, dphy);
+
+ DRM_DEBUG("dphy driver probe success\n");
+
+ return 0;
+}
+
+
+static const struct of_device_id dt_ids[] = {
+ { .compatible = "spacemit,dsi0-phy", },
+ { .compatible = "spacemit,dsi1-phy", },
+ { .compatible = "spacemit,dsi2-phy", },
+ {},
+};
+
+struct platform_driver spacemit_dphy_driver = {
+ .probe = spacemit_dphy_probe,
+ .driver = {
+ .name = "spacemit-dphy-drv",
+ .of_match_table = of_match_ptr(dt_ids),
+ }
+};
+
+//module_platform_driver(spacemit_dphy_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spacemit MIPI DSI PHY driver");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DPHY_H_
+#define _SPACEMIT_DPHY_H_
+
+#include <asm/types.h>
+#include <drm/drm_print.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+
+#include "spacemit_lib.h"
+
+#define DPHY_BITCLK_DEFAULT 614400000
+#define DPHY_ESCCLK_DEFAULT 51200000
+
+enum spacemit_dphy_lane_map {
+ DPHY_LANE_MAP_0123 = 0,
+ DPHY_LANE_MAP_0312 = 1,
+ DPHY_LANE_MAP_0231 = 2,
+ DPHY_LANE_MAP_MAX
+};
+
+enum spacemit_dphy_status {
+ DPHY_STATUS_UNINIT = 0,
+ DPHY_STATUS_INIT = 1,
+ DPHY_STATUS_MAX
+};
+
+enum spacemit_dphy_bit_clk_src {
+ DPHY_BIT_CLK_SRC_PLL5 = 1,
+ DPHY_BIT_CLK_SRC_MUX = 2,
+ DPHY_BIT_CLK_SRC_MAX
+};
+
+struct spacemit_dphy_timing {
+ uint32_t hs_prep_constant; /* Unit: ns. */
+ uint32_t hs_prep_ui;
+ uint32_t hs_zero_constant;
+ uint32_t hs_zero_ui;
+ uint32_t hs_trail_constant;
+ uint32_t hs_trail_ui;
+ uint32_t hs_exit_constant;
+ uint32_t hs_exit_ui;
+ uint32_t ck_zero_constant;
+ uint32_t ck_zero_ui;
+ uint32_t ck_trail_constant;
+ uint32_t ck_trail_ui;
+ uint32_t req_ready;
+ uint32_t wakeup_constant;
+ uint32_t wakeup_ui;
+ uint32_t lpx_constant;
+ uint32_t lpx_ui;
+};
+
+struct spacemit_dphy_ctx {
+ u8 id;
+ void __iomem *base_addr;
+ uint32_t phy_freq; /*kHz*/
+ uint32_t lane_num;
+ uint32_t esc_clk; /*kHz*/
+ uint32_t half_pll5;
+ enum spacemit_dphy_bit_clk_src clk_src;
+ struct spacemit_dphy_timing dphy_timing;
+ uint32_t dphy_status0; /*status0 reg*/
+ uint32_t dphy_status1; /*status1 reg*/
+ uint32_t dphy_status2; /*status2 reg*/
+
+ enum spacemit_dphy_status status;
+};
+
+struct dphy_core_ops {
+ int (*parse_dt)(struct spacemit_dphy_ctx *ctx, struct device_node *np);
+ void (*init)(struct spacemit_dphy_ctx *ctx);
+ void (*uninit)(struct spacemit_dphy_ctx *ctx);
+ void (*reset)(struct spacemit_dphy_ctx *ctx);
+ void (*get_status)(struct spacemit_dphy_ctx *ctx);
+};
+
+struct spacemit_dphy {
+ struct device dev;
+ struct spacemit_dphy_ctx ctx;
+ struct dphy_core_ops *core;
+};
+
+extern struct list_head dphy_core_head;
+
+#define dphy_core_ops_register(entry) \
+ disp_ops_register(entry, &dphy_core_head)
+#define dphy_core_ops_attach(str) \
+ disp_ops_attach(str, &dphy_core_head)
+
+int spacemit_dphy_resume(struct spacemit_dphy *dphy);
+int spacemit_dphy_suspend(struct spacemit_dphy *dphy);
+int spacemit_dphy_reset(struct spacemit_dphy *dphy);
+int spacemit_dphy_get_status(struct spacemit_dphy *dphy);
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/component.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/trace_events.h>
+#include <linux/of_reserved_mem.h>
+#include <dt-bindings/display/spacemit-dpu.h>
+#include "spacemit_cmdlist.h"
+#include "spacemit_dmmu.h"
+#include "spacemit_drm.h"
+#include "spacemit_dpu.h"
+#include "spacemit_gem.h"
+#include "spacemit_lib.h"
+#include "spacemit_bootloader.h"
+#include "dpu/dpu_saturn.h"
+#include "dpu/dpu_debug.h"
+#include "sysfs/sysfs_display.h"
+#include "dpu/dpu_trace.h"
+
+LIST_HEAD(dpu_core_head);
+
+static int spacemit_dpu_init(struct spacemit_dpu *dpu);
+static int spacemit_dpu_uninit(struct spacemit_dpu *dpu);
+static int dpu_pm_suspend(struct device *dev);
+static int dpu_pm_resume(struct device *dev);
+
+static int spacemit_crtc_atomic_check_color_matrix(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct spacemit_crtc_state *ac = to_spacemit_crtc_state(state);
+ struct drm_property_blob *blob = ac->color_matrix_blob_prop;
+ int *data;
+ int n;
+
+ if (blob){
+ data = (int *)blob->data;
+ for (n = 0; n < 9; n++){
+ if ((data[n] > 8191) || (data[n] < -8192)){
+ DRM_DEBUG("The value of color matrix coeffs is invalid: value %d, n %d\n", data[n], n);
+ return -EINVAL;
+ }
+ else
+ data[n] = data[n] & 0x3FFF;
+ }
+
+ for (n = 9; n < 12; n++){
+ if ((data[n] > 4095) || (data[n] < -4096)){
+ DRM_DEBUG("The value of color matrix offset is invalid: value %d, n %d\n", data[n], n);
+ return -EINVAL;
+ }
+ else
+ data[n] = data[n] & 0x3FFF;
+ }
+ }
+
+ return 0;
+}
+
+static int spacemit_crtc_atomic_check_scaling(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct drm_plane *plane;
+ struct spacemit_crtc_state *ac = to_spacemit_crtc_state(crtc_state);
+ const struct drm_plane_state *pstate;
+ struct spacemit_dpu_scaler *scaler = NULL;
+ struct spacemit_plane_state *spacemit_pstate;
+ u32 i;
+
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ spacemit_pstate = to_spacemit_plane_state(pstate);
+
+ if (spacemit_pstate->use_scl) {
+ for (i = 0; i < MAX_SCALER_NUMS; i++) {
+ scaler = &(ac->scalers[i]);
+ if (scaler->in_use == 0x0 || scaler->rdma_id == spacemit_pstate->rdma_id) {
+ scaler->in_use |= (1 << plane->index);
+ scaler->rdma_id = spacemit_pstate->rdma_id;
+ break;
+ }
+ }
+
+ if (i == MAX_SCALER_NUMS)
+ return -EINVAL;
+ }
+ }
+
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ spacemit_pstate = to_spacemit_plane_state(pstate);
+
+ if (spacemit_pstate->rdma_id != RDMA_INVALID_ID) {
+ for (i = 0; i < MAX_SCALER_NUMS; i++) {
+ scaler = &(ac->scalers[i]);
+ if (scaler->rdma_id == spacemit_pstate->rdma_id)
+ spacemit_pstate->scaler_id = i;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* crtc actual mclk depends on max(mclk, aclk) */
+static int spacemit_crtc_atomic_update_mclk(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct spacemit_crtc_state *new_ac = to_spacemit_crtc_state(crtc->state);
+
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct dpu_clk_context *clk_ctx = NULL;
+
+ if (dpu == NULL)
+ return 0;
+
+ if (!dpu->enable_auto_fc)
+ return 0;
+
+ /* when shutdown, all planes disabled, crtc still work, need keep cur mclk */
+ if (new_ac->real_mclk == 0) {
+ trace_u64_data("new_ac->real_mclk", new_ac->real_mclk);
+ return 0;
+ }
+
+ clk_ctx = &dpu->clk_ctx;
+ cancel_work_sync(&dpu->work_update_clk); /* incase mclk fq doing */
+
+ dpu->cur_mclk = clk_get_rate(clk_ctx->mclk);
+ dpu->new_mclk = clk_round_rate(clk_ctx->mclk, new_ac->real_mclk);
+
+ trace_u64_data("crtc mclk cur", dpu->cur_mclk);
+ trace_u64_data("crtc mclk new", dpu->new_mclk);
+ if (dpu->core && dpu->core->update_clk && (dpu->new_mclk > dpu->cur_mclk)) {
+ trace_u64_data("mclk increase to", dpu->new_mclk);
+ dpu->core->update_clk(dpu, dpu->new_mclk);
+ }
+
+ cancel_work_sync(&dpu->work_update_bw);
+
+ dpu->new_bw = new_ac->bw;
+
+ trace_u64_data("crtc bw cur", dpu->cur_bw);
+ trace_u64_data("crtc bw new", dpu->new_bw);
+
+ if (dpu->core && dpu->core->update_bw && (dpu->new_bw > dpu->cur_bw)) {
+ trace_u64_data("bw increase to", dpu->new_bw);
+ dpu->core->update_bw(dpu, dpu->new_bw);
+ }
+
+ return 0;
+}
+
+/* crtc aclk depends on sum of all rdma bw */
+static int spacemit_crtc_atomic_check_aclk(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ const struct drm_plane_state *pstate;
+ struct drm_plane *plane;
+ struct spacemit_crtc_state *ac = to_spacemit_crtc_state(crtc_state); /* new state */
+ bool scl_en = false;
+ uint64_t afbc_effc = ~0ULL;
+ uint64_t tmp, tmp1;
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ if (!dpu->enable_auto_fc)
+ return 0;
+
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ uint64_t tmp_bw = to_spacemit_plane_state(pstate)->bw;
+ bool tmp_scl_en = to_spacemit_plane_state(pstate)->use_scl;
+ ac->bw += tmp_bw;
+ if (tmp_scl_en) {
+ scl_en = true;
+ if (afbc_effc > to_spacemit_plane_state(pstate)->afbc_effc)
+ afbc_effc = to_spacemit_plane_state(pstate)->afbc_effc;
+ }
+ }
+
+ if (ac->bw == 0)
+ ac->bw = DPU_MIN_QOS_REQ;
+
+ if (ac->bw > (DPU_MAX_QOS_REQ * MHZ2KHZ)) {
+ DRM_INFO("crtc:%lld bandwidth too large\n", ac->bw);
+ return -EINVAL;
+ }
+
+ if (scl_en) {
+ //ac->aclk = max(ac->bw / 16 * 10 / 5, ac->mclk / afbc_effc);
+ tmp = ac->bw;
+ do_div(tmp, 16);
+ tmp = tmp * 100;
+ do_div(tmp, 50);
+ tmp1 = ac->mclk;
+ do_div(tmp1, afbc_effc);
+ ac->aclk = max(tmp, tmp1);
+ }
+ else {
+ //ac->aclk = ac->bw / 16 * 10 / 5;
+ tmp = ac->bw;
+ do_div(tmp, 16);
+ tmp = tmp * 100;
+ do_div(tmp, 50);
+ ac->aclk = tmp;
+ }
+
+ trace_u64_data("crtc calc bw", ac->bw);
+ ac->bw += DPU_MARGIN_QOS_REQ * MHZ2KHZ;
+
+ ac->real_mclk = max(ac->mclk, ac->aclk);
+
+ if (ac->real_mclk < dpu->min_mclk)
+ ac->real_mclk = dpu->min_mclk;
+
+ trace_u64_data("crtc fixed bw", ac->bw);
+ trace_u64_data("crtc calc aclk", ac->aclk);
+ trace_u64_data("crtc calc mclk", ac->mclk);
+ trace_u64_data("crtc calc real_mclk", ac->real_mclk);
+
+ return 0;
+}
+
+/* crtc mclk depends on max of all rdma mclk */
+static int spacemit_crtc_atomic_check_mclk(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ const struct drm_plane_state *pstate;
+ struct drm_plane *plane;
+ struct spacemit_crtc_state *ac = to_spacemit_crtc_state(crtc_state);
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ if (!dpu->enable_auto_fc)
+ return 0;
+
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ uint64_t tmp_mclk = to_spacemit_plane_state(pstate)->mclk;
+ if (ac->mclk < tmp_mclk)
+ ac->mclk = tmp_mclk;
+ }
+
+ return 0;
+}
+
+static int spacemit_crtc_atomic_check_fbmem(struct drm_crtc *crtc,
+ struct drm_crtc_state *crtc_state)
+{
+ struct spacemit_dpu_rdma *rdmas = to_spacemit_crtc_state(crtc_state)->rdmas;
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+
+ const struct drm_plane_state *pstate;
+ struct drm_plane *plane;
+ /* Calc each rdma required fbc mem size */
+ drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+ u32 rdma_id = to_spacemit_plane_state(pstate)->rdma_id;
+ u32 layer_fbcmem_size = to_spacemit_plane_state(pstate)->fbcmem_size;
+ if (rdma_id != RDMA_INVALID_ID) {
+ if (rdmas[rdma_id].mode == UP_DOWN)
+ rdmas[rdma_id].fbcmem.size = max(layer_fbcmem_size,
+ rdmas[rdma_id].fbcmem.size);
+ else
+ rdmas[rdma_id].fbcmem.size += layer_fbcmem_size;
+ }
+ }
+
+ /* Adjust each rdma's fbcmem layout */
+ return dpu->core->adjust_rdma_fbcmem(hwdev, rdmas);
+
+}
+
+static void spacemit_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct videomode vm;
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_mode_set_nofb(dpu->dev_id);
+ drm_display_mode_to_videomode(&crtc->mode, &vm);
+}
+
+static void spacemit_crtc_atomic_enable(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_INFO("%s(power on)\n", __func__);
+ trace_spacemit_crtc_atomic_enable(dpu->dev_id);
+
+ pm_runtime_get_sync(dpu->dev);
+ dpu_pm_resume(dpu->dev);
+
+#ifdef CONFIG_SPACEMIT_DEBUG
+ dpu->is_working = true;
+#endif
+ drm_crtc_vblank_on(&dpu->crtc);
+
+ spacemit_dpu_init(dpu);
+
+ if (!IS_ERR_OR_NULL(dpu->enable_gpio)) {
+ gpiod_direction_output(dpu->enable_gpio, 1);
+ }
+}
+
+static void spacemit_crtc_atomic_disable(struct drm_crtc *crtc,
+ struct drm_atomic_state *old_state)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct drm_device *drm = dpu->crtc.dev;
+
+ DRM_INFO("%s(power off)\n", __func__);
+ trace_spacemit_crtc_atomic_disable(dpu->dev_id);
+
+ if (!IS_ERR_OR_NULL(dpu->enable_gpio)) {
+ gpiod_direction_output(dpu->enable_gpio, 0);
+ }
+
+ spacemit_dpu_uninit(dpu);
+
+ drm_crtc_vblank_off(&dpu->crtc);
+#ifdef CONFIG_SPACEMIT_DEBUG
+ dpu->is_working = false;
+#endif
+
+ dpu_pm_suspend(dpu->dev);
+ pm_runtime_put_sync(dpu->dev);
+
+ spin_lock_irq(&drm->event_lock);
+ if (crtc->state->event) {
+ drm_crtc_send_vblank_event(crtc, crtc->state->event);
+ crtc->state->event = NULL;
+ }
+ spin_unlock_irq(&drm->event_lock);
+}
+
+static int spacemit_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *atomic_state)
+{
+ struct drm_crtc_state *state = drm_atomic_get_new_crtc_state(atomic_state, crtc);
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ int ret = 0;
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_atomic_check(dpu->dev_id);
+
+ ret = spacemit_crtc_atomic_check_scaling(crtc, state);
+
+ if (spacemit_crtc_atomic_check_color_matrix(crtc, state)){
+ DRM_DEBUG("The value of color matrix is invalid\n");
+ return -EINVAL;
+ }
+
+ if (spacemit_crtc_atomic_check_fbmem(crtc, state)) {
+ DRM_DEBUG("Failed to satisfy fbcmem size for all rdmas!\n");
+ return -EINVAL;
+ }
+
+ if (spacemit_crtc_atomic_check_mclk(crtc, state)) {
+ DRM_ERROR("Failed to satisfy mclk for all rdmas!\n");
+ return -EINVAL;
+ }
+
+ if (spacemit_crtc_atomic_check_aclk(crtc, state)) {
+ DRM_INFO("Failed to satisfy aclk for all rdmas!\n");
+ return -EINVAL;
+ }
+ return ret;
+}
+
+static void spacemit_crtc_atomic_begin(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_atomic_begin(dpu->dev_id);
+}
+
+static void spacemit_crtc_atomic_flush(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
+
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, crtc);
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_atomic_flush(dpu->dev_id);
+ // spacemit_dpu_wb_config(dpu);
+ saturn_conf_dpuctrl_color_matrix(dpu, old_state);
+ spacemit_crtc_atomic_update_mclk(crtc, old_state);
+ spacemit_dpu_run(crtc, old_state);
+}
+
+static struct drm_crtc_state *spacemit_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct spacemit_crtc_state *state, *old_state;
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u8 n_rdma, i;
+
+ if (WARN_ON(!crtc->state))
+ return NULL;
+
+ old_state = to_spacemit_crtc_state(crtc->state);
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+ memset(&state->scalers, 0x0, sizeof(struct spacemit_dpu_scaler) * MAX_SCALER_NUMS);
+
+ n_rdma = hwdev->rdma_nums;
+ state->rdmas = kzalloc(sizeof(struct spacemit_dpu_rdma) * n_rdma, GFP_KERNEL);
+ if (!state->rdmas) {
+ kfree(state);
+ return NULL;
+ }
+ /* Rdma use UP_DOWN mode by default */
+ for (i = 0; i < n_rdma; i++) {
+ state->rdmas[i].mode = UP_DOWN;
+ state->rdmas[i].in_use = false;
+ }
+
+ if (state->color_matrix_blob_prop)
+ drm_property_blob_get(state->color_matrix_blob_prop);
+
+ return &state->base;
+}
+
+static void spacemit_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ struct spacemit_crtc_state *spacemit_state = NULL;
+
+ if (state) {
+ spacemit_state = to_spacemit_crtc_state(state);
+ __drm_atomic_helper_crtc_destroy_state(state);
+
+ if (spacemit_state->color_matrix_blob_prop)
+ drm_property_blob_put(spacemit_state->color_matrix_blob_prop);
+
+ kfree(spacemit_state->rdmas);
+ kfree(spacemit_state);
+ }
+}
+
+static void spacemit_crtc_reset(struct drm_crtc *crtc)
+{
+ struct spacemit_crtc_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
+ struct spacemit_drm_private *priv = crtc->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u8 n_rdma;
+
+ if (crtc->state)
+ spacemit_crtc_destroy_state(crtc, crtc->state);
+
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
+
+ n_rdma = hwdev->rdma_nums;
+ state->rdmas = kzalloc(sizeof(struct spacemit_dpu_rdma) * n_rdma, GFP_KERNEL);
+ if (!state->rdmas) {
+ DRM_ERROR("Failed to allocate memory of struct spacemit_dpu_rdma!\n");
+ return;
+ }
+
+}
+
+static int spacemit_crtc_enable_vblank(struct drm_crtc *crtc)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_enable_vblank(dpu->dev_id);
+
+ if (dpu->core && dpu->core->enable_vsync)
+ dpu->core->enable_vsync(dpu);
+
+ return 0;
+}
+
+static void spacemit_crtc_disable_vblank(struct drm_crtc *crtc)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_crtc_disable_vblank(dpu->dev_id);
+
+ if (dpu->core && dpu->core->disable_vsync)
+ dpu->core->disable_vsync(dpu);
+}
+
+static int spacemit_crtc_atomic_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct spacemit_crtc_state *s = to_spacemit_crtc_state(state);
+ bool replaced = false;
+ int ret = 0;
+
+ DRM_DEBUG("%s() name = %s, val = %llu\n",
+ __func__, property->name, val);
+
+ if (property == dpu->color_matrix_property){
+ ret = spacemit_atomic_replace_property_blob_from_id(crtc->dev,
+ &s->color_matrix_blob_prop,
+ val,
+ -1,
+ sizeof(int),
+ &replaced);
+ return ret;
+ } else {
+ DRM_ERROR("property %s is invalid\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spacemit_crtc_atomic_get_property(struct drm_crtc *crtc,
+ const struct drm_crtc_state *state,
+ struct drm_property *property,
+ u64 *val)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+ struct spacemit_crtc_state *s = to_spacemit_crtc_state(state);
+
+ DRM_DEBUG("%s() name = %s\n", __func__, property->name);
+
+ if (property == dpu->color_matrix_property){
+ if (s->color_matrix_blob_prop)
+ *val = (s->color_matrix_blob_prop) ? s->color_matrix_blob_prop->base.id : 0;
+ }
+ else {
+ DRM_ERROR("property %s is invalid\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct drm_crtc_helper_funcs spacemit_crtc_helper_funcs = {
+ .mode_set_nofb = spacemit_crtc_mode_set_nofb,
+ .atomic_check = spacemit_crtc_atomic_check,
+ .atomic_begin = spacemit_crtc_atomic_begin,
+ .atomic_flush = spacemit_crtc_atomic_flush,
+ .atomic_enable = spacemit_crtc_atomic_enable,
+ .atomic_disable = spacemit_crtc_atomic_disable,
+};
+
+static const struct drm_crtc_funcs spacemit_crtc_funcs = {
+ .atomic_get_property = spacemit_crtc_atomic_get_property,
+ .atomic_set_property = spacemit_crtc_atomic_set_property,
+ .destroy = drm_crtc_cleanup,
+ .set_config = drm_atomic_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .reset = spacemit_crtc_reset,
+ .atomic_duplicate_state = spacemit_crtc_duplicate_state,
+ .atomic_destroy_state = spacemit_crtc_destroy_state,
+ .enable_vblank = spacemit_crtc_enable_vblank,
+ .disable_vblank = spacemit_crtc_disable_vblank,
+};
+
+static int spacemit_crtc_create_properties(struct drm_crtc *crtc)
+{
+ struct drm_property *prop;
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_DEBUG("%s()\n", __func__);
+ /* create rotation property */
+
+ prop = drm_property_create(crtc->dev,
+ DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
+ "color_matrix_coef", 0);
+ if (!prop)
+ return -ENOMEM;
+ drm_object_attach_property(&crtc->base, prop, 0);
+ dpu->color_matrix_property = prop;
+
+ return 0;
+}
+
+static int spacemit_crtc_init(struct drm_device *drm, struct drm_crtc *crtc,
+ struct drm_plane *primary, struct device_node *port)
+{
+ int err;
+
+ /*
+ * set crtc port so that drm_of_find_possible_crtcs call works
+ */
+ of_node_put(port);
+ crtc->port = port;
+
+ err = drm_crtc_init_with_planes(drm, crtc, primary, NULL,
+ &spacemit_crtc_funcs, NULL);
+ if (err) {
+ DRM_ERROR("failed to init crtc.\n");
+ return err;
+ }
+
+ drm_mode_crtc_set_gamma_size(crtc, 256);
+
+ drm_crtc_helper_add(crtc, &spacemit_crtc_helper_funcs);
+
+ spacemit_crtc_create_properties(crtc);
+
+ DRM_DEBUG("%s() ok\n", __func__);
+ return 0;
+}
+
+int spacemit_dpu_wb_config(struct spacemit_dpu *dpu)
+{
+ if (dpu->core && dpu->core->wb_config)
+ dpu->core->wb_config(dpu);
+
+ return 0;
+}
+
+int spacemit_dpu_run(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state)
+{
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ DRM_DEBUG("%s() type %d \n", __func__, dpu->type);
+ trace_spacemit_dpu_run(dpu->dev_id);
+
+ if (dpu->core && dpu->core->run)
+ dpu->core->run(crtc, old_state);
+
+ return 0;
+}
+
+int spacemit_dpu_stop(struct spacemit_dpu *dpu)
+{
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+ trace_spacemit_dpu_stop(dpu->dev_id);
+
+ if (dpu->core && dpu->core->stop)
+ dpu->core->stop(dpu);
+
+ drm_crtc_handle_vblank(&dpu->crtc);
+
+ return 0;
+}
+
+static int spacemit_dpu_init(struct spacemit_dpu *dpu)
+{
+ trace_spacemit_dpu_init(dpu->dev_id);
+
+ if (dpu->core && dpu->core->init)
+ dpu->core->init(dpu);
+
+ dpu->is_1st_f = true;
+
+ return 0;
+}
+
+static int spacemit_dpu_uninit(struct spacemit_dpu *dpu)
+{
+ trace_spacemit_dpu_uninit(dpu->dev_id);
+
+ if (dpu->core && dpu->core->uninit)
+ dpu->core->uninit(dpu);
+
+ return 0;
+}
+
+static irqreturn_t spacemit_dpu_isr(int irq, void *data)
+{
+ struct spacemit_dpu *dpu = data;
+ u32 int_mask = 0;
+
+ if (dpu->core && dpu->core->isr)
+ int_mask = dpu->core->isr(dpu);
+
+ if (int_mask & DPU_INT_UNDERRUN)
+ DRM_DEBUG("Warning: dpu underrun!\n");
+
+ return IRQ_HANDLED;
+}
+
+static int spacemit_dpu_irqs_init(struct spacemit_dpu *dpu,
+ struct device_node *np, struct platform_device *pdev)
+{
+ int err;
+ int irq;
+
+ /*request irq*/
+ irq = platform_get_irq_byname(pdev, "ONLINE_IRQ");
+ if (irq < 0) {
+ DRM_ERROR("%s: failed to get ONLINE irq number\n", __func__);
+ return -EINVAL;
+ }
+ DRM_DEBUG("dpu online_irq = %d\n", irq);
+ err = request_irq(irq, spacemit_dpu_isr, 0, "DPU_ONLINE", dpu);
+ if (err) {
+ DRM_ERROR("error: dpu request online irq failed\n");
+ return -EINVAL;
+ }
+
+ irq = platform_get_irq_byname(pdev, "OFFLINE_IRQ");
+ if (irq < 0) {
+ DRM_ERROR("%s: failed to get OFFLINE irq number\n", __func__);
+ return -EINVAL;
+ }
+ DRM_DEBUG("dpu offline_irq = %d\n", irq);
+ err = request_irq(irq, spacemit_dpu_isr, 0, "DPU_OFFLINE", dpu);
+ if (err) {
+ DRM_ERROR("error: dpu request offline irq failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void dpu_wq_update_bw(struct work_struct *work)
+{
+ struct spacemit_dpu *dpu =
+ container_of(work, struct spacemit_dpu, work_update_bw);
+
+ if (dpu->core && dpu->core->update_bw) {
+ trace_u64_data("bw decrease to", dpu->new_bw);
+ dpu->core->update_bw(dpu, dpu->new_bw);
+ }
+}
+
+static void dpu_wq_update_clk(struct work_struct *work)
+{
+ struct spacemit_dpu *dpu =
+ container_of(work, struct spacemit_dpu, work_update_clk);
+
+ if (dpu->core && dpu->core->update_clk) {
+ trace_u64_data("mclk decrease to", dpu->new_mclk);
+ dpu->core->update_clk(dpu, dpu->new_mclk);
+ }
+}
+
+#ifdef CONFIG_SPACEMIT_DEBUG
+static bool check_dpu_running_status(struct spacemit_dpu* dpu)
+{
+ return dpu->is_working;
+}
+
+#define to_dpuinfo(_nb) container_of(_nb, struct spacemit_dpu, nb)
+static int dpu_clkoffdet_notifier_handler(struct notifier_block *nb,
+ unsigned long msg, void *data)
+{
+ struct clk_notifier_data *cnd = data;
+ struct spacemit_dpu *dpu = to_dpuinfo(nb);
+
+ if ((__clk_is_enabled(cnd->clk)) && (msg & PRE_RATE_CHANGE) && (cnd->new_rate == 0) && (cnd->old_rate != 0)) {
+ if (dpu->is_dpu_running(dpu))
+ return NOTIFY_BAD;
+ }
+
+ return NOTIFY_OK;
+}
+#endif
+
+static int spacemit_dpu_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm_dev = data;
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ struct device_node *np = dev->of_node;
+ struct drm_plane *plane;
+ int ret;
+#ifdef CONFIG_SPACEMIT_DEBUG
+ struct dpu_clk_context *clk_ctx = NULL;
+#endif
+ DRM_INFO("%s()\n", __func__);
+
+ ret = spacemit_dpu_irqs_init(dpu, np, pdev);
+ if (ret)
+ return ret;
+
+ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ DRM_ERROR("dma_set_mask_and_coherent failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = of_reserved_mem_device_init(dpu->dev);
+ if (ret) {
+ DRM_ERROR("Failed to reserve dpu memory, ret:%d\n", ret);
+ return ret;
+ }
+
+ dpu->dpu_underrun_wq = create_singlethread_workqueue("dpu_underrun_wq");
+ if (!dpu->dpu_underrun_wq) {
+ DRM_ERROR("%s: failed to create wq.\n", __func__);
+ ret = -ESRCH;
+ goto alloc_fail;
+ }
+
+ INIT_WORK(&dpu->work_stop_trace, dpu_underrun_wq_stop_trace);
+ INIT_WORK(&dpu->work_update_clk, dpu_wq_update_clk);
+ INIT_WORK(&dpu->work_update_bw, dpu_wq_update_bw);
+
+ plane = spacemit_plane_init(drm_dev, dpu);
+ if (IS_ERR_OR_NULL(plane)) {
+ ret = PTR_ERR(plane);
+ goto err_destroy_workqueue;
+ }
+
+ ret = spacemit_crtc_init(drm_dev, &dpu->crtc, plane, np);
+ if (ret)
+ goto err_destroy_workqueue;
+
+ // spacemit_wb_init(drm_dev, &dpu->crtc);
+
+ spacemit_dpu_sysfs_init(dev);
+
+#ifdef CONFIG_SPACEMIT_DEBUG
+ clk_ctx = &dpu->clk_ctx;
+ dpu->is_dpu_running = check_dpu_running_status;
+ dpu->nb.notifier_call = dpu_clkoffdet_notifier_handler;
+ clk_notifier_register(clk_ctx->mclk, &dpu->nb);
+#endif
+ DRM_DEBUG("dpu driver probe success\n");
+
+ return 0;
+
+err_destroy_workqueue:
+ destroy_workqueue(dpu->dpu_underrun_wq);
+alloc_fail:
+ of_reserved_mem_device_release(dpu->dev);
+ return ret;
+}
+
+static void spacemit_dpu_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+#ifdef CONFIG_SPACEMIT_DEBUG
+ struct dpu_clk_context *clk_ctx = &dpu->clk_ctx;
+#endif
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ pm_runtime_disable(dev);
+ of_reserved_mem_device_release(dpu->dev);
+ drm_crtc_cleanup(&dpu->crtc);
+
+#ifdef CONFIG_SPACEMIT_DEBUG
+ clk_notifier_unregister(clk_ctx->mclk, &dpu->nb);
+#endif
+}
+
+static const struct component_ops dpu_component_ops = {
+ .bind = spacemit_dpu_bind,
+ .unbind = spacemit_dpu_unbind,
+};
+
+static int spacemit_dpu_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct spacemit_dpu *dpu;
+ struct device_node *np = dev->of_node;
+ struct device_node *rmem_np;
+ struct device_node *fb_np;
+ struct reserved_mem rmem;
+ struct resource rsrv_mem;
+ int ret;
+
+ const char *str;
+ u32 dpu_id;
+ u32 dpu_type;
+ static int dpu_num = 0;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (!dev->of_node) {
+ DRM_DEV_ERROR(dev, "can't find dpu devices\n");
+ return -ENODEV;
+ }
+
+ dpu = devm_kzalloc(dev, sizeof(*dpu), GFP_KERNEL);
+ if (!dpu)
+ return -ENOMEM;
+ dpu->dev = dev;
+ dpu->logo_booton = true;
+ dev_set_drvdata(dev, dpu);
+
+ if (of_property_read_u32(np, "pipeline-id", &dpu_id))
+ return -EINVAL;
+ dpu->dev_id = dpu_id;
+
+ if (of_property_read_u32(np, "type", &dpu_type))
+ return -EINVAL;
+ dpu->type = dpu_type;
+
+ if (!of_property_read_string(np, "ip", &str)) {
+ dpu->core = dpu_core_ops_attach(str);
+ } else
+ DRM_WARN("ip was not found\n");
+
+ /* Clk dts nodes must be parsed in head of pm_runtime_xxx */
+ if (dpu->core && dpu->core->parse_dt)
+ dpu->core->parse_dt(dpu, np);
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ dpu->enable_gpio = devm_gpiod_get_optional(dev, "enable",
+ GPIOD_IN);
+ if (!IS_ERR_OR_NULL(dpu->enable_gpio)) {
+ gpiod_direction_output(dpu->enable_gpio, 0);
+ msleep(50);
+ } else {
+ DRM_DEV_DEBUG(dev, "not found enable gpio\n");
+ }
+
+ if (dpu->type == DSI) {
+ dpu->dsi_reset = devm_reset_control_get_optional_shared(&pdev->dev, "dsi_reset");
+ if (IS_ERR_OR_NULL(dpu->dsi_reset)) {
+ DRM_DEV_DEBUG(dev, "not found dsi_reset\n");
+ }
+ dpu->mclk_reset = devm_reset_control_get_optional_shared(&pdev->dev, "mclk_reset");
+ if (IS_ERR_OR_NULL(dpu->mclk_reset)) {
+ DRM_DEV_DEBUG(dev, "not found mclk_reset\n");
+ }
+ dpu->esc_reset = devm_reset_control_get_optional_shared(&pdev->dev, "esc_reset");
+ if (IS_ERR_OR_NULL(dpu->esc_reset)) {
+ DRM_DEV_DEBUG(dev, "not found esc_reset\n");
+ }
+ dpu->lcd_reset = devm_reset_control_get_optional_shared(&pdev->dev, "lcd_reset");
+ if (IS_ERR_OR_NULL(dpu->lcd_reset)) {
+ DRM_DEV_DEBUG(dev, "not found lcd_reset\n");
+ }
+ } else if (dpu->type == HDMI) {
+ dpu->hdmi_reset = devm_reset_control_get_optional_shared(&pdev->dev, "hdmi_reset");
+ if (IS_ERR_OR_NULL(dpu->hdmi_reset)) {
+ DRM_DEV_DEBUG(dev, "not found hdmi_reset\n");
+ }
+ } else {
+ DRM_DEV_ERROR(dev, "can't find dpu type %d\n", dpu->type);
+ return -ENODEV;
+ }
+
+ dpu_num++;
+ pm_runtime_enable(&pdev->dev);
+ /*
+ * To keep bootloader logo on, below operations must be
+ * done in probe func as power domain framework will turn
+ * on/off lcd power domain before/after probe func.
+ */
+ if (dpu->logo_booton) {
+ pm_runtime_get_sync(&pdev->dev);
+ dpu_pm_resume(&pdev->dev);
+ dpu_pm_suspend(&pdev->dev);
+ pm_runtime_put_sync(&pdev->dev);
+ dpu->logo_booton = false;
+ msleep(10);
+ }
+
+ rmem_np = of_find_node_by_name(NULL, "reserved-memory");
+ if (rmem_np && (dpu_num >= 2)) {
+ fb_np = of_find_node_by_name(rmem_np, "framebuffer");
+ if (fb_np) {
+ ret = of_address_to_resource(fb_np, 0, &rsrv_mem);
+ if (ret < 0) {
+ DRM_DEV_ERROR(dev, "no reserved memory resource find in reserved framebuffer node\n");
+ } else {
+ rmem.base = rsrv_mem.start;
+ rmem.size = resource_size(&rsrv_mem);
+
+ spacemit_dpu_free_bootloader_mem(&rmem);
+ }
+ }
+ }
+
+ return component_add(dev, &dpu_component_ops);
+}
+
+static int spacemit_dpu_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dpu_component_ops);
+ return 0;
+}
+
+static int dpu_pm_suspend(struct device *dev)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ int result;
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ if (dpu->core && dpu->core->disable_clk)
+ dpu->core->disable_clk(dpu);
+
+ if (dpu->type == HDMI) {
+ if (!IS_ERR_OR_NULL(dpu->hdmi_reset)) {
+ result = reset_control_assert(dpu->hdmi_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to assert hdmi_reset: %d\n", result);
+ }
+ }
+ } else if (dpu->type == DSI) {
+
+ if (!IS_ERR_OR_NULL(dpu->lcd_reset)) {
+ result = reset_control_assert(dpu->lcd_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to assert lcd_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->esc_reset)) {
+ result = reset_control_assert(dpu->esc_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to assert esc_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->mclk_reset)) {
+ result = reset_control_assert(dpu->mclk_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to assert mclk_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->dsi_reset)) {
+ result = reset_control_assert(dpu->dsi_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to assert dsi_reset: %d\n", result);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int dpu_pm_resume(struct device *dev)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ int result;
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ if (dpu->type == HDMI) {
+ if (!IS_ERR_OR_NULL(dpu->hdmi_reset)) {
+ result = reset_control_deassert(dpu->hdmi_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to deassert hdmi_reset: %d\n", result);
+ }
+ }
+ } else if (dpu->type == DSI){
+ if (!IS_ERR_OR_NULL(dpu->dsi_reset)) {
+ result = reset_control_deassert(dpu->dsi_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to deassert dsi_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->mclk_reset)) {
+ result = reset_control_deassert(dpu->mclk_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to deassert mclk_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->esc_reset)) {
+ result = reset_control_deassert(dpu->esc_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to deassert esc_reset: %d\n", result);
+ }
+ }
+ if (!IS_ERR_OR_NULL(dpu->lcd_reset)) {
+ result = reset_control_deassert(dpu->lcd_reset);
+ if (result < 0) {
+ DRM_INFO("Failed to deassert lcd_reset: %d\n", result);
+ }
+ }
+ }
+
+ if (dpu->core && dpu->core->enable_clk)
+ dpu->core->enable_clk(dpu);
+
+ return 0;
+}
+
+static int dpu_rt_pm_suspend(struct device *dev)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ return 0;
+}
+
+static int dpu_rt_pm_resume(struct device *dev)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s() type %d\n", __func__, dpu->type);
+
+ return 0;
+}
+
+static const struct dev_pm_ops dpu_pm_ops = {
+ SET_RUNTIME_PM_OPS(dpu_rt_pm_suspend,
+ dpu_rt_pm_resume,
+ NULL)
+};
+
+static const struct of_device_id dpu_match_table[] = {
+ { .compatible = "spacemit,dpu-online0" },
+ { .compatible = "spacemit,dpu-online1" },
+ { .compatible = "spacemit,dpu-online2" },
+ { .compatible = "spacemit,dpu-offline0" },
+ { .compatible = "spacemit,dpu-offline1" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dpu_match_table);
+
+struct platform_driver spacemit_dpu_driver = {
+ .probe = spacemit_dpu_probe,
+ .remove = spacemit_dpu_remove,
+ .driver = {
+ .name = "spacemit-dpu-drv",
+ .of_match_table = dpu_match_table,
+ .pm = &dpu_pm_ops,
+ },
+};
+
+MODULE_DESCRIPTION("Spacemit Display Controller Driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DPU_H_
+#define _SPACEMIT_DPU_H_
+
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <video/videomode.h>
+#include <linux/workqueue.h>
+#include <linux/reset.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio/driver.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_print.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_writeback.h>
+#include <dt-bindings/display/spacemit-dpu.h>
+#include "dpu/saturn_regs/reg_map.h"
+#include "spacemit_drm.h"
+#include "spacemit_lib.h"
+
+#define DPU_INT_UPDATE_DONE BIT(0)
+#define DPU_INT_UNDERRUN BIT(2)
+#define DPU_INT_OVERRUN BIT(3)
+#define DPU_INT_WBDONE BIT(4)
+
+#define N_SCALER_MAX 5
+#define N_DMA_CHANNEL_MAX 12
+#define N_DMA_LAYER_MAX 16
+#define N_COMPOSER_MAX 4
+#define N_COMPOSER_LAYER_MAX 16
+#define N_PANEL_MAX 3
+#define N_OUTCTRL_MAX 3
+#define N_WRITEBACK_MAX 2
+#define N_DISPLAY_MAX 5
+#define N_LUT3D_MAX 3
+#define N_CMDLIST_MAX 14
+
+#define MHZ2HZ 1000000ULL
+#define MHZ2KHZ 1000ULL
+#define DPU_QOS_REQ 1100000
+#define DPU_MIN_QOS_REQ 331070976
+#define DPU_MARGIN_QOS_REQ 900000ULL
+#define DPU_MAX_QOS_REQ (3900000ULL - DPU_MARGIN_QOS_REQ)
+#define RDMA_INVALID_ID (~0)
+#define SCALER_INVALID_ID (u8)(~0)
+
+#define DPU_STOP_TIMEOUT (2000)
+#define DPU_CTRL_MAX_TIMING_INTER1 (0xf)
+
+/*
+#define DPU_PXCLK_DEFAULT 98000000
+#define DPU_MCLK_DEFAULT 307000000
+#define DPU_MCLK_MAX 614400000
+#define DPU_MCLK_MIN 40960000
+#define DPU_AXICLK_DEFAULT 409000000
+#define DPU_ESCCLK_DEFAULT 52000000
+#define DPU_BITCLK_DEFAULT 624000000
+*/
+
+#define DPU_PXCLK_DEFAULT 88000000
+// #define DPU_MCLK_DEFAULT 307200000
+#define DPU_MCLK_DEFAULT 491520000
+#define DPU_MCLK_MAX 614400000
+#define DPU_MCLK_MIN 40960000
+#define DPU_AXICLK_DEFAULT 409000000
+#define DPU_ESCCLK_DEFAULT 51200000
+#define DPU_BITCLK_DEFAULT 614400000
+
+#define MAX_SCALER_NUMS 1
+
+struct spacemit_dpu_scaler {
+ u32 rdma_id;
+ u32 in_use;
+};
+
+enum rdma_mode {
+ UP_DOWN = BIT(0),
+ LEFT_RIGHT = BIT(1),
+};
+
+struct spacemit_dpu_fbcmem {
+ u32 start;
+ u32 size;
+ bool map;
+};
+
+struct spacemit_dpu_rdma {
+ enum rdma_mode mode;
+ struct spacemit_dpu_fbcmem fbcmem;
+ bool in_use;
+};
+
+struct dpu_mmu_tbl {
+ u32 size;
+ void *va;
+ dma_addr_t pa;
+};
+
+struct dpu_clk_context {
+ struct clk *pxclk;
+ struct clk *mclk;
+ struct clk *hclk;
+ struct clk *escclk;
+ struct clk *bitclk;
+ struct clk *hmclk;
+};
+
+struct spacemit_dpu {
+ struct device *dev;
+ struct drm_crtc crtc;
+ struct drm_writeback_connector wb_connector;
+ struct dpu_core_ops *core;
+ struct workqueue_struct *dpu_underrun_wq;
+ struct work_struct work_stop_trace;
+ struct work_struct work_update_clk;
+ struct work_struct work_update_bw;
+ struct dpu_mmu_tbl mmu_tbl;
+ int dev_id;
+ int type;
+ bool enable_dump_reg;
+ bool enable_dump_fps;
+ bool enable_auto_fc;
+ struct timespec64 last_tm;
+
+ bool is_1st_f;
+ bool logo_booton;
+ struct dpu_clk_context clk_ctx;
+ uint64_t new_mclk; /* new frame mclk */
+ uint64_t cur_mclk; /* current frame mclk */
+ unsigned int min_mclk; /* min_mclk of board panel resolution */
+ uint64_t new_bw;
+ uint64_t cur_bw;
+ struct drm_property *color_matrix_property;
+ uint32_t bitclk;
+ uint32_t escclk;
+ struct reset_control *dsi_reset;
+ struct reset_control *mclk_reset;
+ struct reset_control *lcd_reset;
+ struct reset_control *esc_reset;
+ struct reset_control *hdmi_reset;
+ struct gpio_desc *enable_gpio;
+
+#ifdef CONFIG_SPACEMIT_DEBUG
+ bool (*is_dpu_running)(struct spacemit_dpu* dpu);
+ struct notifier_block nb;
+ bool is_working;
+#endif
+};
+
+extern struct list_head dpu_core_head;
+
+static inline struct spacemit_dpu *crtc_to_dpu(struct drm_crtc *crtc)
+{
+ return crtc ? container_of(crtc, struct spacemit_dpu, crtc) : NULL;
+}
+
+struct dpu_core_ops {
+ int (*parse_dt)(struct spacemit_dpu *dpu, struct device_node *np);
+ u32 (*version)(struct spacemit_dpu *dpu);
+ int (*init)(struct spacemit_dpu *dpu);
+ void (*uninit)(struct spacemit_dpu *dpu);
+ void (*run)(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state);
+ void (*stop)(struct spacemit_dpu *dpu);
+ void (*flip)(struct spacemit_dpu *dpu);
+ void (*disable_vsync)(struct spacemit_dpu *dpu);
+ void (*enable_vsync)(struct spacemit_dpu *dpu);
+ u32 (*isr)(struct spacemit_dpu *dpu);
+ int (*modeset)(struct spacemit_dpu *dpu, struct drm_mode_modeinfo *mode);
+ int (*enable_clk)(struct spacemit_dpu *dpu);
+ int (*disable_clk)(struct spacemit_dpu *dpu);
+ int (*cal_layer_fbcmem_size)(struct drm_plane *plane, \
+ struct drm_plane_state *state);
+ int (*adjust_rdma_fbcmem)(struct spacemit_hw_device *hwdev, \
+ struct spacemit_dpu_rdma *rdmas);
+ int (*calc_plane_mclk_bw)(struct drm_plane *plane, \
+ struct drm_plane_state *state);
+ void (*wb_config)(struct spacemit_dpu *dpu);
+ int (*update_clk)(struct spacemit_dpu *dpu, uint64_t mclk);
+ int (*update_bw)(struct spacemit_dpu *dpu, uint64_t bw);
+};
+
+#define dpu_core_ops_register(entry) \
+ disp_ops_register(entry, &dpu_core_head)
+#define dpu_core_ops_attach(str) \
+ disp_ops_attach(str, &dpu_core_head)
+
+int spacemit_dpu_run(struct drm_crtc *crtc,
+ struct drm_crtc_state *old_state);
+int spacemit_dpu_stop(struct spacemit_dpu *dpu);
+int spacemit_dpu_wb_config(struct spacemit_dpu *dpu);
+
+struct spacemit_plane {
+ struct drm_plane plane;
+ struct spacemit_hw_device *hwdev;
+ struct drm_property *rdma_id_property;
+ struct drm_property *solid_color_property;
+ struct drm_property *hdr_coef_property;
+ struct drm_property *scale_coef_property;
+ u32 hw_pid;
+};
+
+struct spacemit_plane_state {
+ struct drm_plane_state state;
+ u32 rdma_id;
+ u32 solid_color;
+ /*
+ * scaler id. As long as its rdma channel is identical with any
+ * one uses the scaler, it's set to the scaler's id, even if it
+ * doesn't really use the scaler.
+ */
+ u8 scaler_id;
+ /* hw format */
+ u8 format;
+ bool use_scl;
+ bool is_offline; //to indicate rdma is offline
+ bool right_image;
+ u32 fbcmem_size;
+ uint64_t mclk; //DPU MCLK = MAX(Mclk, Aclk) of all planes
+ uint64_t bw; //BandWidth = SUM(BW_single) * 1.08
+ struct dpu_mmu_tbl mmu_tbl;
+ struct cmdlist cl;
+ uint64_t afbc_effc;
+ struct drm_property_blob *hdr_coefs_blob_prop;
+ struct drm_property_blob *scale_coefs_blob_prop;
+};
+
+struct spacemit_plane *to_spacemit_plane(struct drm_plane *plane);
+
+static inline struct
+spacemit_plane_state *to_spacemit_plane_state(const struct drm_plane_state *state)
+{
+ return container_of(state, struct spacemit_plane_state, state);
+}
+
+struct spacemit_crtc_state {
+ struct drm_crtc_state base;
+ struct spacemit_dpu_scaler scalers[MAX_SCALER_NUMS];
+ struct spacemit_dpu_rdma *rdmas;
+ uint64_t mclk; /* max of all rdma mclk */
+ uint64_t bw; /* sum of all rdma bw*/
+ uint64_t aclk; /* based on bw */
+ uint64_t real_mclk; /* real_mclk = max(mclk, aclk) */
+ struct drm_property_blob *color_matrix_blob_prop;
+};
+
+#define to_spacemit_crtc_state(x) container_of(x, struct spacemit_crtc_state, base)
+
+struct drm_plane *spacemit_plane_init(struct drm_device *drm,
+ struct spacemit_dpu *dpu);
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DPU_REG_H_
+#define _SPACEMIT_DPU_REG_H_
+
+enum REG_FILED_TYPE {
+ FIELD_DEF, //reg field is rw
+ FIELD_W1C, //reg field is write 1 cleared
+ FIELD_W1S, //reg field is write 1 set
+ FIELD_W0C, //reg field is write 0 cleared
+};
+
+#define dpu_read_reg(hwdev, module_name, module_base, field) \
+ ({ u32 __v = (((volatile module_name *)(module_base + hwdev->base))->field); \
+ __v; }) \
+
+#define dpu_write_reg_common(hwdev, module_name, module_base, field, data, type) \
+{ \
+ volatile module_name *module = (module_name *)(module_base + hwdev->base); \
+ /* Ensure register value is as expected */ \
+ module->field = data; \
+}
+
+#define dpu_write_reg(hwdev, module_name, module_base, field, data) \
+ dpu_write_reg_common(hwdev, module_name, module_base, field, data, FIELD_DEF)
+
+#define dpu_write_reg_w1c(hwdev, module_name, module_base, field, data) \
+ dpu_write_reg_common(hwdev, module_name, module_base, field, data, FIELD_W1C)
+
+#define dpu_write_reg_w1s(hwdev, module_name, module_base, field, data) \
+ dpu_write_reg_common(hwdev, module_name, module_base, field, data, FIELD_W1S)
+
+#define dpu_write_reg_w0c(hwdev, module_name, module_base, field, data) \
+ dpu_write_reg_common(hwdev, module_name, module_base, field, data, FIELD_W0C)
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fbdev_generic.h>
+#include <drm/drm_aperture.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_debugfs.h>
+#include <drm/drm_gem_framebuffer_helper.h>
+#include <drm/drm_ioctl.h>
+#include <drm/drm_of.h>
+#include <linux/component.h>
+#include <linux/mutex.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/kernel.h>
+
+#include "spacemit_drm.h"
+#include "spacemit_dmmu.h"
+#include "spacemit_gem.h"
+
+#define DRIVER_NAME "spacemit"
+#define DRIVER_DESC "Spacemit SoCs' DRM Driver"
+#define DRIVER_DATE "20231115"
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+
+void spacemit_drm_atomic_commit_tail(struct drm_atomic_state *old_state)
+{
+ struct drm_device *dev = old_state->dev;
+
+ drm_atomic_helper_commit_modeset_disables(dev, old_state);
+
+ drm_atomic_helper_commit_modeset_enables(dev, old_state);
+
+ drm_atomic_helper_commit_planes(dev, old_state,
+ DRM_PLANE_COMMIT_ACTIVE_ONLY);
+
+ // spacemit_wb_atomic_commit(dev, old_state);
+
+ drm_atomic_helper_wait_for_flip_done(dev, old_state);
+
+ drm_atomic_helper_commit_hw_done(old_state);
+
+ drm_atomic_helper_cleanup_planes(dev, old_state);
+}
+
+static const struct drm_mode_config_helper_funcs spacemit_drm_mode_config_helper = {
+ .atomic_commit_tail = spacemit_drm_atomic_commit_tail,
+};
+
+static const struct drm_mode_config_funcs spacemit_drm_mode_config_funcs = {
+ .fb_create = drm_gem_fb_create,
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = drm_atomic_helper_commit,
+};
+
+static void spacemit_drm_mode_config_init(struct drm_device *drm)
+{
+ drm_mode_config_init(drm);
+
+ /*HW has no limitation of min width and min height,
+ even for YUV format, which is limitated in plane check*/
+ drm->mode_config.min_width = 1;
+ drm->mode_config.min_height = 1;
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+ //drm->mode_config.allow_fb_modifiers = true;
+
+ drm->mode_config.funcs = &spacemit_drm_mode_config_funcs;
+ drm->mode_config.helper_private = &spacemit_drm_mode_config_helper;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#define FRAMEBUFFER_DUMP_PATH "/tmp"
+static int spacemit_framebuffer_dump(struct drm_plane *plane) {
+ unsigned int buffer_size = 0;
+ int i, j;
+ void *mmu_tbl_vaddr = NULL;
+ phys_addr_t dpu_buffer_paddr = 0;
+ void __iomem *dpu_buffer_vaddr = NULL;
+ loff_t pos = 0;
+ struct file *filep = NULL;
+ struct drm_framebuffer *fb;
+ char file_name[128];
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(plane->state);
+
+ fb = plane->state->fb;
+ if (!fb) {
+ return -EINVAL;
+ }
+
+ for (i = 0; i < fb->format->num_planes; i++) {
+ if (fb->obj[i]) {
+ char format[5];
+ format[0] = (fb->format->format & 0xFF);
+ format[1] = ((fb->format->format >> 8) & 0xFF);
+ format[2] = ((fb->format->format >> 16) & 0xFF);
+ format[3] = ((fb->format->format >> 24) & 0xFF);
+ format[4] = '\0';
+
+ if (fb->format->is_yuv) {
+ snprintf(file_name, 100, "%s/plane%d_fb%d_%s_planes%d_%dx%d.%s", FRAMEBUFFER_DUMP_PATH, plane->base.id, fb->base.id,
+ format, i, fb->width, fb->height, "yuv");
+ } else {
+ snprintf(file_name, 100, "%s/plane%d_fb%d_%s_planes%d_%dx%d.%s", FRAMEBUFFER_DUMP_PATH, plane->base.id, fb->base.id,
+ format, i, fb->width, fb->height, "rgb");
+ }
+
+ mmu_tbl_vaddr = spacemit_pstate->mmu_tbl.va;
+ buffer_size = plane->state->fb->obj[i]->size >> PAGE_SHIFT;
+ filep = filp_open(file_name, O_RDWR | O_APPEND | O_CREAT, 0644);
+
+ if (IS_ERR(filep)) {
+ DRM_ERROR("Open file %s failed!\n", file_name);
+ return -EINVAL;
+ }
+ for (j = 0; j < buffer_size; j++) {
+ dpu_buffer_paddr = *(volatile u32 __force *)mmu_tbl_vaddr;
+ dpu_buffer_paddr = dpu_buffer_paddr << PAGE_SHIFT;
+ if (dpu_buffer_paddr >= 0x80000000UL) {
+ dpu_buffer_paddr += 0x80000000UL;
+ }
+ dpu_buffer_vaddr = phys_to_virt((unsigned long)dpu_buffer_paddr);
+ mmu_tbl_vaddr += 4;
+ kernel_write(filep, (void *)dpu_buffer_vaddr, PAGE_SIZE, &pos);
+ }
+ filp_close(filep, NULL);
+ filep = NULL;
+ DRM_INFO("dump framebuffer: %s\n", file_name);
+ }
+
+ }
+
+ return 0;
+}
+
+static int spacemit_drm_dump_show(struct seq_file *s, void *data)
+{
+ struct drm_info_node *node = s->private;
+ struct drm_minor *minor = node->minor;
+ struct drm_device *drm_dev = minor->dev;
+ struct drm_plane *plane;
+ struct drm_framebuffer *fb;
+
+ DRM_INFO("%s()\n", __func__);
+ mutex_lock(&drm_dev->mode_config.fb_lock);
+ drm_for_each_fb(fb, drm_dev) {
+ DRM_INFO("framebuffer[%u] \n", fb->base.id);
+ drm_for_each_plane(plane, drm_dev) {
+ if (plane->state->fb != fb)
+ continue;
+
+ spacemit_framebuffer_dump(plane);
+ }
+ }
+ mutex_unlock(&drm_dev->mode_config.fb_lock);
+
+ return 0;
+}
+
+static const struct drm_info_list spacemit_debugfs_files[] = {
+ { "dump", spacemit_drm_dump_show, 0 },
+};
+
+static void spacemit_drm_debugfs_init(struct drm_minor *minor)
+{
+ DRM_DEBUG("%s()\n", __func__);
+ drm_debugfs_create_files(spacemit_debugfs_files,
+ ARRAY_SIZE(spacemit_debugfs_files),
+ minor->debugfs_root,
+ minor);
+}
+#endif
+
+static const struct file_operations spacemit_drm_fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+ .compat_ioctl = drm_compat_ioctl,
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+ .mmap = spacemit_gem_mmap,
+};
+
+const struct vm_operations_struct spacemit_gem_vm_ops = {
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static struct drm_driver spacemit_drm_drv = {
+ .driver_features = DRIVER_GEM | DRIVER_MODESET |
+ DRIVER_ATOMIC | DRIVER_HAVE_IRQ,
+ .fops = &spacemit_drm_fops,
+ .dumb_create = spacemit_gem_dumb_create,
+ .gem_prime_import_sg_table = spacemit_gem_prime_import_sg_table,
+#ifdef CONFIG_DEBUG_FS
+ .debugfs_init = spacemit_drm_debugfs_init,
+#endif
+
+ .name = DRIVER_NAME,
+ .desc = DRIVER_DESC,
+ .date = DRIVER_DATE,
+ .major = DRIVER_MAJOR,
+ .minor = DRIVER_MINOR,
+};
+
+static int spacemit_drm_bind(struct device *dev)
+{
+ struct drm_device *drm;
+ struct spacemit_drm_private *priv;
+ int err;
+
+ DRM_DEBUG("%s()\n", __func__);
+ /* Remove existing drivers that may own the framebuffer memory. */
+ err = drm_aperture_remove_framebuffers(&spacemit_drm_drv);
+ if (err) {
+ DRM_ERROR("Failed to remove existing framebuffers - %d.\n", err);
+ return err;
+ }
+
+ drm = drm_dev_alloc(&spacemit_drm_drv, dev);
+ if (IS_ERR(drm))
+ return PTR_ERR(drm);
+
+ priv = dev_get_drvdata(dev);
+ priv->ddev = drm;
+ drm->dev_private = priv;
+ priv->dev = dev;
+
+ spacemit_drm_mode_config_init(drm);
+
+ /* bind and init sub drivers */
+ err = component_bind_all(drm->dev, drm);
+ if (err) {
+ DRM_ERROR("failed to bind all component.\n");
+ goto err_dc_cleanup;
+ }
+
+ /* vblank init */
+ err = drm_vblank_init(drm, drm->mode_config.num_crtc);
+ if (err) {
+ DRM_ERROR("failed to initialize vblank.\n");
+ goto err_unbind_all;
+ }
+ // /* with irq_enabled = true, we can use the vblank feature. */
+ // drm->irq_enabled = true;
+
+ /* reset all the states of crtc/plane/encoder/connector */
+ drm_mode_config_reset(drm);
+
+ /* init kms poll for handling hpd */
+ drm_kms_helper_poll_init(drm);
+
+ /* force detection after connectors init */
+ drm_helper_hpd_irq_event(drm);
+
+ err = drm_dev_register(drm, 0);
+ if (err < 0)
+ goto err_kms_helper_poll_fini;
+ drm_fbdev_generic_setup(drm, 32);
+
+ return 0;
+
+err_kms_helper_poll_fini:
+ drm_kms_helper_poll_fini(drm);
+err_unbind_all:
+ component_unbind_all(drm->dev, drm);
+err_dc_cleanup:
+ drm_mode_config_cleanup(drm);
+ drm_dev_put(drm);
+ return err;
+}
+
+static void spacemit_drm_put_dev(struct drm_device *dev)
+{
+ DRM_DEBUG("\n");
+
+ if (!dev) {
+ DRM_ERROR("cleanup called no dev\n");
+ return;
+ }
+
+ drm_dev_unregister(dev);
+ drm_dev_put(dev);
+}
+
+static void spacemit_drm_unbind(struct device *dev)
+{
+ DRM_DEBUG("%s()\n", __func__);
+ spacemit_drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops drm_component_ops = {
+ .bind = spacemit_drm_bind,
+ .unbind = spacemit_drm_unbind,
+};
+
+static int compare_of(struct device *dev, void *data)
+{
+ struct device_node *np = data;
+
+ DRM_DEBUG("compare %s\n", np->full_name);
+
+ return dev->of_node == np;
+}
+
+int spacemit_drm_of_component_probe(struct device *dev,
+ int (*compare_of)(struct device *, void *),
+ const struct component_master_ops *m_ops)
+{
+ struct device_node *ep, *port, *remote;
+ struct component_match *match = NULL;
+ int i;
+
+ if (!dev->of_node)
+ return -EINVAL;
+
+ /*
+ * Bind the crtc's ports first, so that drm_of_find_possible_crtcs()
+ * called from encoder's .bind callbacks works as expected
+ */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(dev->of_node, "ports", i);
+ if (!port)
+ break;
+
+ if (of_device_is_available(port->parent))
+ drm_of_component_match_add(dev, &match, compare_of,
+ port);
+
+ of_node_put(port);
+ }
+
+ if (i == 0) {
+ dev_err(dev, "missing 'ports' property\n");
+ return -ENODEV;
+ }
+
+ if (!match) {
+ dev_err(dev, "no available port\n");
+ return -ENODEV;
+ }
+
+ /*
+ * For bound crtcs, bind the encoders attached to their remote endpoint
+ */
+ for (i = 0; ; i++) {
+ port = of_parse_phandle(dev->of_node, "ports", i);
+ if (!port)
+ break;
+
+ if (!of_device_is_available(port->parent)) {
+ of_node_put(port);
+ continue;
+ }
+
+ for_each_child_of_node(port, ep) {
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
+ continue;
+ } else if (!of_device_is_available(remote->parent)) {
+ dev_warn(dev, "parent device of %pOF is not available\n",
+ remote);
+ of_node_put(remote);
+ continue;
+ }
+
+ drm_of_component_match_add(dev, &match, compare_of,
+ remote);
+ of_node_put(remote);
+ }
+ of_node_put(port);
+ }
+
+ return component_master_add_with_match(dev, m_ops, match);
+}
+
+static int spacemit_drm_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct spacemit_drm_private *priv;
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret)
+ DRM_ERROR("dma_set_mask_and_coherent failed (%d)\n", ret);
+
+ /* Allocate and initialize the driver private structure. */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ // if (of_property_read_u32(np, "hw_ver", &priv->hw_ver))
+ // return -EINVAL;
+
+ priv->contig_mem = false;
+
+ priv->num_pipes = of_count_phandle_with_args(np, "ports", NULL);
+ if (priv->num_pipes <= 0) {
+ DRM_ERROR("no ports are defined\n");
+ return -EINVAL;
+ }
+
+ priv->hwdev = (struct spacemit_hw_device *)of_device_get_match_data(&pdev->dev);
+
+ priv->cmdlist_num = 0;
+ priv->cmdlist_regs = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!priv->cmdlist_regs)
+ return -ENOMEM;
+
+ priv->cmdlist_groups = kzalloc(sizeof(struct cmdlist *) * \
+ priv->hwdev->rdma_nums, GFP_KERNEL);
+ if (!priv->cmdlist_groups)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->hwdev->phy_addr = r->start;
+ priv->hwdev->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->hwdev->base))
+ return PTR_ERR(priv->hwdev->base);
+
+ return spacemit_drm_of_component_probe(&pdev->dev, compare_of, &drm_component_ops);
+}
+
+static int spacemit_drm_remove(struct platform_device *pdev)
+{
+ component_master_del(&pdev->dev, &drm_component_ops);
+ return 0;
+}
+
+static void spacemit_drm_shutdown(struct platform_device *pdev)
+{
+ struct spacemit_drm_private *priv = dev_get_drvdata(&pdev->dev);
+ struct drm_device *drm = priv->ddev;
+
+ if (!drm) {
+ DRM_WARN("drm device is not available, no shutdown\n");
+ return;
+ }
+
+ drm_atomic_helper_shutdown(drm);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int spacemit_drm_suspend(struct device *dev)
+{
+ struct spacemit_drm_private *priv = dev_get_drvdata(dev);
+ struct drm_device *drm = priv->ddev;
+
+ return drm_mode_config_helper_suspend(drm);
+}
+
+static int spacemit_drm_resume(struct device *dev)
+{
+ struct spacemit_drm_private *priv = dev_get_drvdata(dev);
+ struct drm_device *drm = priv->ddev;
+
+ return drm_mode_config_helper_resume(drm);
+}
+#endif
+
+static const struct dev_pm_ops spacemit_drm_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(spacemit_drm_suspend,
+ spacemit_drm_resume)
+};
+
+static const struct of_device_id drm_match_table[] = {
+ {
+ .compatible = "spacemit,saturn-hdmi",
+ .data = &spacemit_dp_devices[SATURN_HDMI],
+ },
+ {
+ .compatible = "spacemit,saturn-le",
+ .data = &spacemit_dp_devices[SATURN_LE],
+ },
+ {},
+
+};
+MODULE_DEVICE_TABLE(of, drm_match_table);
+
+static struct platform_driver spacemit_drm_driver = {
+ .probe = spacemit_drm_probe,
+ .remove = spacemit_drm_remove,
+ .shutdown = spacemit_drm_shutdown,
+ .driver = {
+ .name = "spacemit-drm-drv",
+ .of_match_table = drm_match_table,
+ .pm = &spacemit_drm_pm_ops,
+ },
+};
+
+static struct platform_driver * const spacemit_drm_drivers[] = {
+ &spacemit_drm_driver,
+ &spacemit_dpu_driver,
+ &spacemit_dsi_driver,
+ &spacemit_dphy_driver,
+};
+
+#ifdef MODULE
+extern int dsi_core_register(void);
+extern int dpu_core_register(void);
+extern int dphy_core_register(void);
+extern int display_class_init(void);
+void drm_core_register(void)
+{
+ display_class_init();
+ dsi_core_register();
+ dpu_core_register();
+ dphy_core_register();
+}
+#endif
+static int __init spacemit_drm_drivers_init(void)
+{
+#ifdef MODULE
+ drm_core_register();
+#endif
+ return platform_register_drivers(spacemit_drm_drivers,
+ ARRAY_SIZE(spacemit_drm_drivers));
+}
+
+static void __exit spacemit_drm_drivers_exit(void)
+{
+ platform_unregister_drivers(spacemit_drm_drivers,
+ ARRAY_SIZE(spacemit_drm_drivers));
+}
+
+module_init(spacemit_drm_drivers_init);
+module_exit(spacemit_drm_drivers_exit);
+
+MODULE_DESCRIPTION("Spacemit DRM KMS Master Driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DRM_H_
+#define _SPACEMIT_DRM_H_
+
+#include <drm/drm_print.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_vblank.h>
+#include <drm/drm_probe_helper.h>
+#include <linux/dma-mapping.h>
+#include "spacemit_cmdlist.h"
+
+struct spacemit_hw_device {
+ void __iomem *base;
+ phys_addr_t phy_addr;
+ u8 plane_nums;
+ u8 rdma_nums;
+ const struct spacemit_hw_rdma *rdmas;
+ u8 n_formats;
+ const struct dpu_format_id *formats;
+ u8 n_fbcmems;
+ const u32 *fbcmem_sizes;
+ const u32 *rdma_fixed_fbcmem_sizes;
+ u32 solid_color_shift;
+ int hdr_coef_size;
+ int scale_coef_size;
+ bool is_hdmi;
+};
+
+struct spacemit_drm_private {
+ struct drm_device *ddev;
+ struct device *dev;
+ struct spacemit_hw_device *hwdev;
+ int hw_ver;
+ bool contig_mem;
+ int num_pipes;
+ struct cmdlist **cmdlist_groups;
+ struct cmdlist_reg *cmdlist_regs;
+ int cmdlist_num;
+};
+
+extern struct platform_driver spacemit_dpu_driver;
+extern struct platform_driver spacemit_dphy_driver;
+extern struct platform_driver spacemit_dsi_driver;
+
+int spacemit_wb_init(struct drm_device *drm, struct drm_crtc *crtc);
+void spacemit_wb_atomic_commit(struct drm_device *drm, struct drm_atomic_state *old_state);
+
+#endif /* _SPACEMIT_DRM_H_ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_of.h>
+#include <linux/component.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_graph.h>
+#include <linux/pm_runtime.h>
+#include <video/mipi_display.h>
+#include "spacemit_lib.h"
+#include "spacemit_dpu.h"
+#include "spacemit_dsi.h"
+#include "sysfs/sysfs_display.h"
+
+LIST_HEAD(dsi_core_head);
+
+static void spacemit_dsi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct spacemit_dsi *dsi = encoder_to_dsi(encoder);
+ //struct spacemit_dpu *dpu = crtc_to_dpu(encoder->crtc);
+ void __iomem *addr = (void __iomem *)ioremap(0xd421a1a8, 100);
+
+ DRM_INFO("%s()\n", __func__);
+
+ if (!dsi->core || !dsi->core->dsi_open) {
+ DRM_ERROR("%s(), dsi->core is null!\n", __func__);
+ return;
+ }
+
+ /* Dsi online setup */
+ writel(0x40000001, addr);
+ writel(0x1, addr + 0x10);
+
+ dsi->core->dsi_open(&dsi->ctx, false);
+
+ if (dsi->panel) {
+ drm_panel_prepare(dsi->panel);
+ drm_panel_enable(dsi->panel);
+ }
+
+ if (dsi->core && dsi->core->dsi_ready_for_datatx)
+ dsi->core->dsi_ready_for_datatx(&dsi->ctx);
+}
+
+static void spacemit_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct spacemit_dsi *dsi = encoder_to_dsi(encoder);
+ struct spacemit_dpu *dpu = crtc_to_dpu(encoder->crtc);
+
+ DRM_INFO("%s()\n", __func__);
+
+ spacemit_dpu_stop(dpu);
+
+ if (dsi->core && dsi->core->dsi_close_datatx)
+ dsi->core->dsi_close_datatx(&dsi->ctx);
+
+ if (dsi->panel) {
+ drm_panel_disable(dsi->panel);
+ drm_panel_unprepare(dsi->panel);
+ }
+
+ if (dsi->core && dsi->core->dsi_close)
+ dsi->core->dsi_close(&dsi->ctx);
+}
+
+static void spacemit_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct spacemit_dsi *dsi = encoder_to_dsi(encoder);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ drm_display_mode_to_videomode(mode, &dsi->ctx.vm);
+}
+
+static int spacemit_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ DRM_DEBUG("%s()\n", __func__);
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs spacemit_encoder_helper_funcs = {
+ .atomic_check = spacemit_dsi_encoder_atomic_check,
+ .mode_set = spacemit_dsi_encoder_mode_set,
+ .enable = spacemit_dsi_encoder_enable,
+ .disable = spacemit_dsi_encoder_disable,
+};
+
+static const struct drm_encoder_funcs spacemit_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int spacemit_dsi_encoder_init(struct drm_device *drm, struct spacemit_dsi *dsi)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct device *dev = dsi->host.dev;
+ u32 crtc_mask;
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ crtc_mask = drm_of_find_possible_crtcs(drm, dev->of_node);
+ if (!crtc_mask) {
+ DRM_ERROR("failed to find crtc mask\n");
+ return -EINVAL;
+ }
+ DRM_INFO("find possible crtcs: 0x%08x\n", crtc_mask);
+
+ encoder->possible_crtcs = crtc_mask;
+ ret = drm_encoder_init(drm, encoder, &spacemit_encoder_funcs,
+ DRM_MODE_ENCODER_DSI, NULL);
+ if (ret) {
+ DRM_ERROR("failed to init dsi encoder\n");
+ return ret;
+ }
+
+ drm_encoder_helper_add(encoder, &spacemit_encoder_helper_funcs);
+
+ return 0;
+}
+
+static int spacemit_dsi_find_panel(struct spacemit_dsi *dsi)
+{
+ struct device *dev = dsi->host.dev;
+ struct device_node *child, *lcds_node;
+ struct drm_panel *panel;
+
+ /* search /lcds child node first */
+ lcds_node = of_find_node_by_path("/lcds");
+ for_each_child_of_node(lcds_node, child) {
+ panel = of_drm_find_panel(child);
+ if (!IS_ERR(panel)) {
+ dsi->panel = panel;
+ of_node_put(child);
+ return 0;
+ }
+ }
+
+ /*
+ * If /lcds child node search failed, we search
+ * the child of dsi host node.
+ */
+ for_each_child_of_node(dev->of_node, child) {
+ panel = of_drm_find_panel(child);
+ if (panel) {
+ dsi->panel = panel;
+ of_node_put(child);
+ return 0;
+ }
+ }
+
+ DRM_ERROR("of_drm_find_panel() failed\n");
+ return -ENODEV;
+}
+
+static int spacemit_dsi_phy_attach(struct spacemit_dsi *dsi)
+{
+ struct device *dev;
+
+ dev = spacemit_disp_pipe_get_output(&dsi->dev);
+ if (!dev)
+ return -ENODEV;
+
+ dsi->ctx.phy = dev_get_drvdata(dev);
+ if (!dsi->ctx.phy) {
+ DRM_ERROR("dsi attach phy failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void spacemit_dsi_get_mipi_info(struct device_node *lcd_node, struct spacemit_mipi_info *mipi_info)
+{
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32(lcd_node, "height", &val);
+ if (ret)
+ DRM_ERROR("of get mipi height failed\n");
+ else
+ mipi_info->height = val;
+
+ ret = of_property_read_u32(lcd_node, "width", &val);
+ if (ret)
+ DRM_ERROR("of get mipi width failed\n");
+ else
+ mipi_info->width = val;
+
+ ret = of_property_read_u32(lcd_node, "hfp", &val);
+ if (ret)
+ DRM_ERROR("of get mipi hfp failed\n");
+ else
+ mipi_info->hfp = val;
+
+ ret = of_property_read_u32(lcd_node, "hbp", &val);
+ if (ret)
+ DRM_ERROR("of get mipi hbp failed\n");
+ else
+ mipi_info->hbp = val;
+
+ ret = of_property_read_u32(lcd_node, "hsync", &val);
+ if (ret)
+ DRM_ERROR("of get mipi hsync failed\n");
+ else
+ mipi_info->hsync = val;
+
+ ret = of_property_read_u32(lcd_node, "vfp", &val);
+ if (ret)
+ DRM_ERROR("of get mipi vfp failed\n");
+ else
+ mipi_info->vfp = val;
+
+ ret = of_property_read_u32(lcd_node, "vbp", &val);
+ if (ret)
+ DRM_ERROR("of get mipi vbp failed\n");
+ else
+ mipi_info->vbp = val;
+
+ ret = of_property_read_u32(lcd_node, "vsync", &val);
+ if (ret)
+ DRM_ERROR("of get mipi vsync failed\n");
+ else
+ mipi_info->vsync = val;
+
+ ret = of_property_read_u32(lcd_node, "fps", &val);
+ if (ret)
+ DRM_ERROR("of get mipi fps failed\n");
+ else
+ mipi_info->fps = val;
+
+ ret = of_property_read_u32(lcd_node, "work-mode", &val);
+ if (ret)
+ DRM_ERROR("of get mipi work-mode failed\n");
+ else
+ mipi_info->work_mode = val;
+
+ ret = of_property_read_u32(lcd_node, "rgb-mode", &val);
+ if (ret)
+ DRM_ERROR("of get mipi rgb-mode failed\n");
+ else
+ mipi_info->rgb_mode = val;
+
+ ret = of_property_read_u32(lcd_node, "lane-number", &val);
+ if (ret)
+ DRM_ERROR("of get mipi lane-number failed\n");
+ else
+ mipi_info->lane_number = val;
+
+ ret = of_property_read_u32(lcd_node, "phy-bit-clock", &val);
+ if (ret)
+ mipi_info->phy_bit_clock = DPHY_BITCLK_DEFAULT;
+ else
+ mipi_info->phy_bit_clock = val;
+
+
+ ret = of_property_read_u32(lcd_node, "phy-esc-clock", &val);
+ if (ret)
+ mipi_info->phy_esc_clock = DPHY_ESCCLK_DEFAULT;
+ else
+ mipi_info->phy_esc_clock = val;
+
+ ret = of_property_read_u32(lcd_node, "split-enable", &val);
+ if (ret)
+ DRM_ERROR("of get mipi split-enable failed\n");
+ else
+ mipi_info->split_enable = val;
+
+ ret = of_property_read_u32(lcd_node, "eotp-enable", &val);
+ if (ret)
+ DRM_ERROR("of get mipi eotp-enable failed\n");
+ else
+ mipi_info->eotp_enable = val;
+
+ ret = of_property_read_u32(lcd_node, "burst-mode", &val);
+ if (ret)
+ DRM_ERROR("of get mipi burst-mode failed\n");
+ else
+ mipi_info->burst_mode = val;
+}
+
+static void spacemit_dsi_get_advanced_info(struct spacemit_dsi *dsi, struct spacemit_mipi_info *mipi_info)
+{
+ struct spacemit_dsi_device *ctx = &dsi->ctx;
+ struct spacemit_dsi_advanced_setting *adv_setting = &ctx->adv_setting;
+ struct device_node *np = dsi->dev.of_node;
+ int ret;
+
+ /*advanced_setting*/
+ ret = of_property_read_u32(np, "lpm_frame_en", &adv_setting->lpm_frame_en);
+ if(ret)
+ adv_setting->lpm_frame_en = LPM_FRAME_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "last_line_turn", &adv_setting->last_line_turn);
+ if(ret)
+ adv_setting->last_line_turn = LAST_LINE_TURN_DEFAULT;
+
+ ret = of_property_read_u32(np, "hex_slot_en", &adv_setting->hex_slot_en);
+ if(ret)
+ adv_setting->hex_slot_en = HEX_SLOT_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "hsa_pkt_en", &adv_setting->hsa_pkt_en);
+ if(ret){
+ if(mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE)
+ adv_setting->hsa_pkt_en = HSA_PKT_EN_DEFAULT_SYNC_PULSE;
+ else
+ adv_setting->hsa_pkt_en = HSA_PKT_EN_DEFAULT_OTHER;
+ }
+
+ ret = of_property_read_u32(np, "hse_pkt_en", &adv_setting->hse_pkt_en);
+ if(ret){
+ if(mipi_info->burst_mode == DSI_BURST_MODE_NON_BURST_SYNC_PULSE)
+ adv_setting->hse_pkt_en = HSE_PKT_EN_DEFAULT_SYNC_PULSE;
+ else
+ adv_setting->hse_pkt_en = HSE_PKT_EN_DEFAULT_OTHER;
+ }
+
+ ret = of_property_read_u32(np, "hbp_pkt_en", &adv_setting->hbp_pkt_en);
+ if(ret)
+ adv_setting->hbp_pkt_en = HBP_PKT_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "hfp_pkt_en", &adv_setting->hfp_pkt_en);
+ if(ret)
+ adv_setting->hfp_pkt_en = HFP_PKT_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "hex_pkt_en", &adv_setting->hex_pkt_en);
+ if(ret)
+ adv_setting->hex_pkt_en = HEX_PKT_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "hlp_pkt_en", &adv_setting->hlp_pkt_en);
+ if(ret)
+ adv_setting->hlp_pkt_en = HLP_PKT_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "auto_dly_dis", &adv_setting->auto_dly_dis);
+ if(ret)
+ adv_setting->auto_dly_dis = AUTO_DLY_DIS_DEFAULT;
+
+ ret = of_property_read_u32(np, "timing_check_dis", &adv_setting->timing_check_dis);
+ if(ret)
+ adv_setting->timing_check_dis = TIMING_CHECK_DIS_DEFAULT;
+
+ ret = of_property_read_u32(np, "hact_wc_en", &adv_setting->hact_wc_en);
+ if(ret)
+ adv_setting->hact_wc_en = HACT_WC_EN_DEFAULT;
+
+ ret = of_property_read_u32(np, "auto_wc_dis", &adv_setting->auto_wc_dis);
+ if(ret)
+ adv_setting->auto_wc_dis = AUTO_WC_DIS_DEFAULT;
+
+ ret = of_property_read_u32(np, "vsync_rst_en", &adv_setting->vsync_rst_en);
+ if(ret)
+ adv_setting->vsync_rst_en = VSYNC_RST_EN_DEFAULT;
+}
+
+static int spacemit_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *slave)
+{
+ struct spacemit_dsi *dsi = host_to_dsi(host);
+ struct spacemit_dsi_device *ctx = &dsi->ctx;
+ struct spacemit_mipi_info *mipi_info = &ctx->mipi_info;
+ struct device_node *lcd_node;
+ int ret;
+
+ DRM_INFO("%s()\n", __func__);
+
+ dsi->slave = slave;
+
+ ret = spacemit_dsi_phy_attach(dsi);
+ if (ret)
+ return ret;
+
+ ret = spacemit_dsi_find_panel(dsi);
+ if (ret)
+ return ret;
+
+ lcd_node = dsi->panel->dev->of_node;
+
+ spacemit_dsi_get_mipi_info(lcd_node, mipi_info);
+ spacemit_dsi_get_advanced_info(dsi, mipi_info);
+
+ return 0;
+}
+
+static int spacemit_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *slave)
+{
+ DRM_INFO("%s()\n", __func__);
+ /* do nothing */
+ return 0;
+}
+
+static ssize_t spacemit_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct spacemit_dsi *dsi = host_to_dsi(host);
+ struct spacemit_dsi_cmd_desc cmd;
+ struct spacemit_dsi_rx_buf dbuf = {0x0};
+
+ cmd.cmd_type = msg->type;
+ cmd.length = msg->tx_len;
+ memcpy(cmd.data, msg->tx_buf, cmd.length);
+
+ if(msg->flags & MIPI_DSI_MSG_USE_LPM)
+ cmd.lp = 1;
+ else
+ cmd.lp = 0;
+
+ if (msg->rx_buf && msg->rx_len) {
+ if (dsi->core && dsi->core->dsi_read_cmds)
+ dsi->core->dsi_read_cmds(&dsi->ctx, &dbuf, &cmd, 1);
+ memcpy(msg->rx_buf, dbuf.data, 1);
+ return 0;
+ }
+
+ if (msg->tx_buf && msg->tx_len) {
+ if (dsi->core && dsi->core->dsi_write_cmds)
+ dsi->core->dsi_write_cmds(&dsi->ctx, &cmd, 1);
+ }
+
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops spacemit_dsi_host_ops = {
+ .attach = spacemit_dsi_host_attach,
+ .detach = spacemit_dsi_host_detach,
+ .transfer = spacemit_dsi_host_transfer,
+};
+
+static int spacemit_dsi_host_init(struct device *dev, struct spacemit_dsi *dsi)
+{
+ int ret;
+
+ dsi->host.dev = dev;
+ dsi->host.ops = &spacemit_dsi_host_ops;
+
+ ret = mipi_dsi_host_register(&dsi->host);
+ if (ret)
+ DRM_ERROR("failed to register dsi host\n");
+
+ return ret;
+}
+
+static int spacemit_dsi_connector_get_modes(struct drm_connector *connector)
+{
+ struct spacemit_dsi *dsi = connector_to_dsi(connector);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ return drm_panel_get_modes(dsi->panel, connector);
+}
+
+static enum drm_mode_status
+spacemit_dsi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ enum drm_mode_status mode_status = MODE_OK;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ return mode_status;
+}
+
+static struct drm_encoder *
+spacemit_dsi_connector_best_encoder(struct drm_connector *connector)
+{
+ struct spacemit_dsi *dsi = connector_to_dsi(connector);
+
+ DRM_DEBUG("%s()\n", __func__);
+ return &dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs spacemit_dsi_connector_helper_funcs = {
+ .get_modes = spacemit_dsi_connector_get_modes,
+ .mode_valid = spacemit_dsi_connector_mode_valid,
+ .best_encoder = spacemit_dsi_connector_best_encoder,
+};
+
+static enum drm_connector_status
+spacemit_dsi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct spacemit_dsi *dsi = connector_to_dsi(connector);
+
+ DRM_DEBUG("%s() dsi subconnector type %d status %d\n", __func__, dsi->ctx.dsi_subconnector, dsi->ctx.connector_status);
+
+ if (SPACEMIT_DSI_SUBCONNECTOR_DP == dsi->ctx.dsi_subconnector)
+ return dsi->ctx.connector_status;
+ else
+ return connector_status_connected;
+}
+
+static void spacemit_dsi_connector_destroy(struct drm_connector *connector)
+{
+ DRM_INFO("%s()\n", __func__);
+
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs spacemit_dsi_atomic_connector_funcs = {
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = spacemit_dsi_connector_detect,
+ .destroy = spacemit_dsi_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int spacemit_dsi_connector_init(struct drm_device *drm, struct spacemit_dsi *dsi)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_connector *connector = &dsi->connector;
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ ret = drm_connector_init(drm, connector,
+ &spacemit_dsi_atomic_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ if (ret) {
+ DRM_ERROR("drm_connector_init() failed\n");
+ return ret;
+ }
+
+ drm_connector_helper_add(connector,
+ &spacemit_dsi_connector_helper_funcs);
+
+ //drm_mode_connector_attach_encoder(connector, encoder);
+ drm_connector_attach_encoder(connector, encoder);
+
+ return 0;
+}
+
+static int __maybe_unused spacemit_dsi_bridge_attach(struct spacemit_dsi *dsi)
+{
+ struct drm_encoder *encoder = &dsi->encoder;
+ struct drm_bridge *bridge = dsi->bridge;
+ struct device *dev = dsi->host.dev;
+ struct device_node *bridge_node;
+ int ret;
+
+ bridge_node = of_graph_get_remote_node(dev->of_node, 2, 0);
+ if (!bridge_node)
+ return 0;
+
+ bridge = of_drm_find_bridge(bridge_node);
+ if (!bridge) {
+ DRM_ERROR("of_drm_find_bridge() failed\n");
+ return -ENODEV;
+ }
+ dsi->bridge = bridge;
+
+ ret = drm_bridge_attach(encoder, bridge, NULL, 0);
+ if (ret) {
+ DRM_ERROR("failed to attach external bridge\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static irqreturn_t spacemit_dsi_isr(int irq, void *data)
+{
+ struct spacemit_dsi *dsi = data;
+ DRM_DEBUG("%s: dsi Enter\n", __func__);
+
+ if (dsi->core && dsi->core->isr)
+ dsi->core->isr(&dsi->ctx);
+
+ return IRQ_HANDLED;
+}
+
+static int spacemit_dsi_irq_request(struct spacemit_dsi *dsi)
+{
+ int ret;
+ int irq;
+
+ irq = irq_of_parse_and_map(dsi->host.dev->of_node, 0);
+ if (irq) {
+ DRM_DEBUG("dsi irq num = %d\n", irq);
+ ret = request_irq(irq, spacemit_dsi_isr, 0, "DSI", dsi);
+ if (ret) {
+ DRM_ERROR("dsi failed to request irq int0!\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int spacemit_dsi_bind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm = data;
+ struct spacemit_dsi *dsi = dev_get_drvdata(dev);
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ ret = spacemit_dsi_encoder_init(drm, dsi);
+ if (ret)
+ goto cleanup_host;
+
+ ret = spacemit_dsi_connector_init(drm, dsi);
+ if (ret)
+ goto cleanup_encoder;
+
+ ret = spacemit_dsi_irq_request(dsi);
+ if (ret)
+ goto cleanup_connector;
+
+ return 0;
+
+cleanup_connector:
+ drm_connector_cleanup(&dsi->connector);
+cleanup_encoder:
+ drm_encoder_cleanup(&dsi->encoder);
+cleanup_host:
+ mipi_dsi_host_unregister(&dsi->host);
+ return ret;
+}
+
+static void spacemit_dsi_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ /* do nothing */
+ DRM_DEBUG("%s()\n", __func__);
+
+}
+
+static const struct component_ops dsi_component_ops = {
+ .bind = spacemit_dsi_bind,
+ .unbind = spacemit_dsi_unbind,
+};
+
+static int spacemit_dsi_device_create(struct spacemit_dsi *dsi, struct device *parent)
+{
+ int ret;
+
+ dsi->dev.class = display_class;
+ dsi->dev.parent = parent;
+ dsi->dev.of_node = parent->of_node;
+ dev_set_name(&dsi->dev, "dsi%d", dsi->ctx.id);
+ dev_set_drvdata(&dsi->dev, dsi);
+
+ ret = device_register(&dsi->dev);
+ if (ret)
+ DRM_ERROR("dsi device register failed\n");
+
+ return ret;
+}
+
+static int spacemit_dsi_context_init(struct spacemit_dsi *dsi, struct device_node *np)
+{
+ struct spacemit_dsi_device *ctx = &dsi->ctx;
+ struct resource r;
+ u32 tmp;
+
+ if (dsi->core && dsi->core->parse_dt)
+ dsi->core->parse_dt(&dsi->ctx, np);
+
+ if (of_address_to_resource(np, 0, &r)) {
+ DRM_ERROR("parse dsi ctrl reg base failed\n");
+ return -ENODEV;
+ }
+ ctx->base_addr = (void __iomem *)ioremap(r.start, resource_size(&r));
+ if (NULL == ctx->base_addr) {
+ DRM_ERROR("dsi ctrl reg base ioremap failed\n");
+ return -ENODEV;
+ }
+
+ ctx->dsi_subconnector = SPACEMIT_DSI_SUBCONNECTOR_MIPI_DSI;
+ ctx->previous_connector_status = connector_status_connected;
+ ctx->connector_status = connector_status_connected;
+
+ if (!of_property_read_u32(np, "dev-id", &tmp))
+ ctx->id = tmp;
+
+ return 0;
+}
+
+static int spacemit_dsi_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spacemit_dsi *dsi;
+ const char *str;
+ int ret;
+
+ DRM_INFO("%s()\n", __func__);
+
+ dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+ if (!dsi) {
+ DRM_ERROR("failed to allocate dsi data.\n");
+ return -ENOMEM;
+ }
+
+ if (!of_property_read_string(np, "ip", &str))
+ dsi->core = dsi_core_ops_attach(str);
+ else
+ DRM_WARN("error: 'ip' was not found\n");
+
+ ret = spacemit_dsi_context_init(dsi, np);
+ if (ret)
+ return -EINVAL;
+
+ spacemit_dsi_device_create(dsi, &pdev->dev);
+ spacemit_dsi_sysfs_init(&dsi->dev);
+ platform_set_drvdata(pdev, dsi);
+
+ ret = spacemit_dsi_host_init(&pdev->dev, dsi);
+ if (ret)
+ return ret;
+
+ return component_add(&pdev->dev, &dsi_component_ops);
+}
+
+static int spacemit_dsi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dsi_component_ops);
+
+ return 0;
+}
+
+static const struct of_device_id spacemit_dsi_of_match[] = {
+ { .compatible = "spacemit,dsi0-host" },
+ { .compatible = "spacemit,dsi1-host" },
+ { .compatible = "spacemit,dsi2-host" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, spacemit_dsi_of_match);
+
+struct platform_driver spacemit_dsi_driver = {
+ .probe = spacemit_dsi_probe,
+ .remove = spacemit_dsi_remove,
+ .driver = {
+ .name = "spacemit-dsi-drv",
+ .of_match_table = spacemit_dsi_of_match,
+ },
+};
+
+MODULE_DESCRIPTION("Spacemit MIPI DSI HOST Controller Driver");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_DSI_H_
+#define _SPACEMIT_DSI_H_
+
+#include <linux/of.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <video/videomode.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
+
+#include "spacemit_lib.h"
+#include "spacemit_dphy.h"
+
+/* define LCD_IS_READY to bypass kernel dsi driver */
+/* #define LCD_IS_READY */
+
+/*advanced setting*/
+#define LPM_FRAME_EN_DEFAULT 0
+#define LAST_LINE_TURN_DEFAULT 0
+#define HEX_SLOT_EN_DEFAULT 0
+#define HSA_PKT_EN_DEFAULT_SYNC_PULSE 1
+#define HSA_PKT_EN_DEFAULT_OTHER 0
+#define HSE_PKT_EN_DEFAULT_SYNC_PULSE 1
+#define HSE_PKT_EN_DEFAULT_OTHER 0
+#define HBP_PKT_EN_DEFAULT 1
+#define HFP_PKT_EN_DEFAULT 0
+#define HEX_PKT_EN_DEFAULT 0
+#define HLP_PKT_EN_DEFAULT 0
+#define AUTO_DLY_DIS_DEFAULT 0
+#define TIMING_CHECK_DIS_DEFAULT 0
+#define HACT_WC_EN_DEFAULT 1
+#define AUTO_WC_DIS_DEFAULT 0
+#define VSYNC_RST_EN_DEFAULT 1
+
+#define MAX_TX_CMD_COUNT 256
+#define MAX_RX_DATA_COUNT 64
+
+enum spacemit_mipi_burst_mode{
+ DSI_BURST_MODE_NON_BURST_SYNC_PULSE = 0,
+ DSI_BURST_MODE_NON_BURST_SYNC_EVENT = 1,
+ DSI_BURST_MODE_BURST = 2,
+ DSI_BURST_MODE_MAX
+};
+
+enum spacemit_mipi_input_data_mode{
+ DSI_INPUT_DATA_RGB_MODE_565 = 0,
+ DSI_INPUT_DATA_RGB_MODE_666PACKET = 1,
+ DSI_INPUT_DATA_RGB_MODE_666UNPACKET = 2,
+ DSI_INPUT_DATA_RGB_MODE_888 = 3,
+ DSI_INPUT_DATA_RGB_MODE_MAX
+};
+
+enum spacemit_dsi_work_mode {
+ SPACEMIT_DSI_MODE_VIDEO,
+ SPACEMIT_DSI_MODE_CMD,
+ SPACEMIT_DSI_MODE_MAX
+};
+
+enum spacemit_dsi_cmd_type {
+ SPACEMIT_DSI_DCS_SWRITE = 0x5,
+ SPACEMIT_DSI_DCS_SWRITE1 = 0x15,
+ SPACEMIT_DSI_DCS_LWRITE = 0x39,
+ SPACEMIT_DSI_DCS_READ = 0x6,
+ SPACEMIT_DSI_GENERIC_LWRITE = 0x29,
+ SPACEMIT_DSI_GENERIC_READ1 = 0x14,
+ SPACEMIT_DSI_SET_MAX_PKT_SIZE = 0x37,
+};
+
+enum spacemit_dsi_tx_mode {
+ SPACEMIT_DSI_HS_MODE = 0,
+ SPACEMIT_DSI_LP_MODE = 1,
+};
+
+enum spacemit_dsi_rx_data_type {
+ SPACEMIT_DSI_ACK_ERR_RESP = 0x2,
+ SPACEMIT_DSI_EOTP = 0x8,
+ SPACEMIT_DSI_GEN_READ1_RESP = 0x11,
+ SPACEMIT_DSI_GEN_READ2_RESP = 0x12,
+ SPACEMIT_DSI_GEN_LREAD_RESP = 0x1A,
+ SPACEMIT_DSI_DCS_READ1_RESP = 0x21,
+ SPACEMIT_DSI_DCS_READ2_RESP = 0x22,
+ SPACEMIT_DSI_DCS_LREAD_RESP = 0x1C,
+};
+
+enum spacemit_dsi_polarity {
+ SPACEMIT_DSI_POLARITY_POS = 0,
+ SPACEMIT_DSI_POLARITY_NEG,
+ SPACEMIT_DSI_POLARITY_MAX
+};
+
+enum spacemit_dsi_te_mode {
+ SPACEMIT_DSI_TE_MODE_NO = 0,
+ SPACEMIT_DSI_TE_MODE_A,
+ SPACEMIT_DSI_TE_MODE_B,
+ SPACEMIT_DSI_TE_MODE_C,
+ SPACEMIT_DSI_TE_MODE_MAX,
+};
+
+enum spacemit_dsi_event_id {
+ SPACEMIT_DSI_EVENT_ERROR,
+ SPACEMIT_DSI_EVENT_MAX,
+};
+
+enum spacemit_dsi_status {
+ DSI_STATUS_UNINIT = 0,
+ DSI_STATUS_OPENED = 1,
+ DSI_STATUS_INIT = 2,
+ DSI_STATUS_MAX
+};
+
+struct spacemit_dsi_advanced_setting {
+ uint32_t lpm_frame_en; /*return to LP mode every frame*/
+ uint32_t last_line_turn;
+ uint32_t hex_slot_en;
+ uint32_t hsa_pkt_en;
+ uint32_t hse_pkt_en;
+ uint32_t hbp_pkt_en; /*bit:18*/
+ uint32_t hfp_pkt_en; /*bit:20*/
+ uint32_t hex_pkt_en;
+ uint32_t hlp_pkt_en; /*bit:22*/
+ uint32_t auto_dly_dis;
+ uint32_t timing_check_dis;
+ uint32_t hact_wc_en;
+ uint32_t auto_wc_dis;
+ uint32_t vsync_rst_en;
+};
+
+struct spacemit_mipi_info {
+ unsigned int height;
+ unsigned int width;
+ unsigned int hfp; /*pixel*/
+ unsigned int hbp;
+ unsigned int hsync;
+ unsigned int vfp; /*line*/
+ unsigned int vbp;
+ unsigned int vsync;
+ unsigned int fps;
+
+ unsigned int work_mode; /*command_mode, video_mode*/
+ unsigned int rgb_mode;
+ unsigned int lane_number;
+ unsigned int phy_bit_clock;
+ unsigned int phy_esc_clock;
+ unsigned int split_enable;
+ unsigned int eotp_enable;
+
+ /*for video mode*/
+ unsigned int burst_mode;
+
+ /*for cmd mode*/
+ unsigned int te_enable;
+ unsigned int vsync_pol;
+ unsigned int te_pol;
+ unsigned int te_mode;
+
+ /*The following fields need not be set by panel*/
+ unsigned int real_fps;
+};
+
+struct spacemit_dsi_cmd_desc {
+ enum spacemit_dsi_cmd_type cmd_type;
+ uint8_t lp;
+ uint32_t delay; /* time to delay */
+ uint32_t length; /* cmds length */
+ uint8_t data[MAX_TX_CMD_COUNT];
+};
+
+struct spacemit_dsi_rx_buf {
+ enum spacemit_dsi_rx_data_type data_type;
+ uint32_t length; /* cmds length */
+ uint8_t data[MAX_RX_DATA_COUNT];
+};
+
+enum spacemit_dsi_subconnector {
+ SPACEMIT_DSI_SUBCONNECTOR_MIPI_DSI = 0,
+ SPACEMIT_DSI_SUBCONNECTOR_HDMI = 1,
+ SPACEMIT_DSI_SUBCONNECTOR_DP = 2,
+ SPACEMIT_DSI_SUBCONNECTOR_eDP = 3,
+};
+
+struct spacemit_dsi_device {
+ uint16_t id;
+ void __iomem *base_addr;
+ struct spacemit_dsi_advanced_setting adv_setting;
+ struct spacemit_mipi_info mipi_info;
+ struct videomode vm;
+ struct spacemit_dphy *phy;
+ enum spacemit_dsi_status status;
+ enum drm_connector_status previous_connector_status;
+ enum drm_connector_status connector_status;
+ enum spacemit_dsi_subconnector dsi_subconnector;
+};
+
+struct dsi_core_ops {
+ int (*parse_dt)(struct spacemit_dsi_device *ctx, struct device_node *np);
+ int (*isr)(struct spacemit_dsi_device *ctx);
+ int (*dsi_open)(struct spacemit_dsi_device *ctx, bool ready);
+ int (*dsi_close)(struct spacemit_dsi_device *ctx);
+ int (*dsi_write_cmds)(struct spacemit_dsi_device *ctx, struct spacemit_dsi_cmd_desc *cmds, int count);
+ int (*dsi_read_cmds)(struct spacemit_dsi_device *ctx, struct spacemit_dsi_rx_buf *dbuf,
+ struct spacemit_dsi_cmd_desc *cmds, int count);
+ int (*dsi_ready_for_datatx)(struct spacemit_dsi_device *ctx);
+ int (*dsi_close_datatx)(struct spacemit_dsi_device *ctx);
+};
+
+struct spacemit_dsi {
+ struct device dev;
+ struct mipi_dsi_host host;
+ struct mipi_dsi_device *slave;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ struct dsi_core_ops *core;
+ struct spacemit_dsi_device ctx;
+};
+
+extern struct list_head dsi_core_head;
+
+#define dsi_core_ops_register(entry) \
+ disp_ops_register(entry, &dsi_core_head)
+#define dsi_core_ops_attach(str) \
+ disp_ops_attach(str, &dsi_core_head)
+
+#define encoder_to_dsi(encoder) \
+ container_of(encoder, struct spacemit_dsi, encoder)
+#define host_to_dsi(host) \
+ container_of(host, struct spacemit_dsi, host)
+#define connector_to_dsi(connector) \
+ container_of(connector, struct spacemit_dsi, connector)
+
+#endif /* _SPACEMIT_DSI_H_ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-map-ops.h>
+#include <drm/drm_prime.h>
+#include <drm/drm_gem_dma_helper.h>
+
+#include "spacemit_gem.h"
+#include "spacemit_dmmu.h"
+#include "spacemit_drm.h"
+
+static const unsigned int orders[] = {8, 4, 0};
+static const int num_orders = ARRAY_SIZE(orders);
+
+static struct page *__alloc_largest_available(size_t size,
+ unsigned int max_order)
+{
+ struct page *page;
+ unsigned int order;
+ gfp_t gfp_flags;
+ int i;
+
+ for (i = 0; i < num_orders; i++) {
+ order = orders[i];
+
+ if (size < (PAGE_SIZE << order))
+ continue;
+ if (max_order < order)
+ continue;
+
+ gfp_flags = (GFP_HIGHUSER | __GFP_ZERO |
+ __GFP_COMP | __GFP_RECLAIM);
+
+ page = alloc_pages(gfp_flags, order);
+ if (!page)
+ continue;
+
+ return page;
+ }
+
+ return NULL;
+}
+
+static int spacemit_gem_sysmem_alloc(struct drm_device *drm,
+ struct spacemit_gem_object *spacemit_obj,
+ size_t size)
+{
+ struct sg_table *sgt;
+ struct scatterlist *sg;
+ struct list_head pages;
+ struct page *page, *tmp_page;
+ size_t size_remaining = size;
+ unsigned int max_order = orders[0];
+ int i = 0;
+ u32 page_nums = PAGE_ALIGN(size) >> PAGE_SHIFT;
+ struct spacemit_drm_private *priv = drm->dev_private;
+
+
+ sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
+ if (!sgt)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pages);
+ if (priv->contig_mem) {
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+ return -ENOMEM;
+#else
+ page = dma_alloc_from_contiguous(drm->dev, page_nums, 0, 0);
+ if (!page) {
+ kfree(sgt);
+ DRM_ERROR("Failed to alloc %zd bytes continous mem\n", size);
+ return -ENOMEM;
+ }
+ list_add_tail(&page->lru, &pages);
+ i++;
+#endif
+ } else {
+ while (size_remaining > 0) {
+ if (fatal_signal_pending(current))
+ goto free_pages;
+
+ page = __alloc_largest_available(size_remaining, max_order);
+ if (!page)
+ goto free_pages;
+
+ list_add_tail(&page->lru, &pages);
+ size_remaining -= page_size(page);
+ max_order = compound_order(page);
+ i++;
+ }
+ }
+
+ if (sg_alloc_table(sgt, i, GFP_KERNEL))
+ goto free_pages;
+
+ sg = sgt->sgl;
+ list_for_each_entry_safe(page, tmp_page, &pages, lru) {
+ if (priv->contig_mem)
+ sg_set_page(sg, page, page_nums << PAGE_SHIFT, 0);
+ else
+ sg_set_page(sg, page, page_size(page), 0);
+ sg = sg_next(sg);
+ list_del(&page->lru);
+ }
+
+ dma_map_sgtable(drm->dev, sgt, DMA_BIDIRECTIONAL, 0);
+ dma_unmap_sgtable(drm->dev, sgt, DMA_BIDIRECTIONAL, 0);
+
+ spacemit_obj->sgt = sgt;
+
+ return 0;
+
+free_pages:
+ list_for_each_entry_safe(page, tmp_page, &pages, lru) {
+ if (priv->contig_mem)
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+ nop();
+#else
+ dma_release_from_contiguous(drm->dev, page, page_nums);
+#endif
+ else
+ __free_pages(page, compound_order(page));
+ }
+ kfree(sgt);
+
+ return -ENOMEM;
+}
+
+static void spacemit_gem_sysmem_free(struct spacemit_gem_object *spacemit_obj)
+{
+ struct sg_table *sgt = spacemit_obj->sgt;
+ struct scatterlist *sg;
+ int i;
+ struct drm_device *drm = spacemit_obj->base.dev;
+ struct spacemit_drm_private *priv = drm->dev_private;
+
+ if (!sgt) {
+ return;
+ }
+
+ for_each_sgtable_sg(sgt, sg, i) {
+ struct page *page = sg_page(sg);
+ if (priv->contig_mem)
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+ nop();
+#else
+ dma_release_from_contiguous(drm->dev, page, sg->length >> PAGE_SHIFT);
+#endif
+ else
+ __free_pages(page, compound_order(page));
+ }
+
+ sg_free_table(sgt);
+ kfree(sgt);
+}
+
+static int spacemit_gem_alloc_buf(struct drm_device *drm,
+ struct spacemit_gem_object *spacemit_obj,
+ size_t size)
+{
+ int ret;
+
+ ret = spacemit_gem_sysmem_alloc(drm, spacemit_obj, size);
+ if (ret) {
+ DRM_ERROR("SPACEMIT_GEM: failed to allocate %zu byte buffer", size);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void spacemit_gem_free_buf(struct spacemit_gem_object *spacemit_obj)
+{
+ spacemit_gem_sysmem_free(spacemit_obj);
+}
+
+static void spacemit_gem_free_object(struct drm_gem_object *gem_obj)
+{
+ struct spacemit_gem_object *spacemit_obj = to_spacemit_obj(gem_obj);
+
+ if (gem_obj->import_attach) {
+ drm_prime_gem_destroy(gem_obj, spacemit_obj->sgt);
+ } else {
+ spacemit_gem_free_buf(spacemit_obj);
+ }
+
+ drm_gem_object_release(gem_obj);
+
+ kfree(spacemit_obj);
+}
+
+static struct sg_table *__dup_sg_table(struct sg_table *sgt)
+{
+ struct sg_table *new_sgt;
+ struct scatterlist *sg, *new_sg;
+ int ret, i;
+
+ new_sgt = kzalloc(sizeof(*new_sgt), GFP_KERNEL);
+ if (!new_sgt)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sg_alloc_table(new_sgt, sgt->orig_nents, GFP_KERNEL);
+ if (ret) {
+ kfree(new_sgt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ new_sg = new_sgt->sgl;
+ for_each_sgtable_sg(sgt, sg, i) {
+ sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset);
+ new_sg = sg_next(new_sg);
+ }
+
+ return new_sgt;
+}
+
+static struct sg_table *spacemit_gem_prime_get_sg_table(struct drm_gem_object *gem_obj)
+{
+ struct spacemit_gem_object *spacemit_obj = to_spacemit_obj(gem_obj);
+
+ return __dup_sg_table(spacemit_obj->sgt);
+}
+
+int spacemit_gem_prime_vmap(struct drm_gem_object *gem_obj, struct iosys_map *map)
+{
+ struct spacemit_gem_object *spacemit_obj = to_spacemit_obj(gem_obj);
+ struct sg_page_iter piter;
+ int ret = 0;
+ void *vaddr;
+ int npages = PAGE_ALIGN(gem_obj->size) >> PAGE_SHIFT;
+ struct page **pages, **tmp;
+ pgprot_t pgprot = pgprot_writecombine(PAGE_KERNEL);
+
+ mutex_lock(&spacemit_obj->vmap_lock);
+
+
+ if (spacemit_obj->vmap_cnt)
+ goto vmap_success;
+
+ pages = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
+ tmp = pages;
+ if (!pages)
+ goto vmap_fail;
+ for_each_sgtable_page(spacemit_obj->sgt, &piter, 0) {
+ WARN_ON(tmp - pages >= npages);
+ *(tmp++) = sg_page_iter_page(&piter);
+ }
+ vaddr = vmap(pages, npages, VM_MAP, pgprot);
+ kvfree(pages);
+
+ if (!vaddr)
+ goto vmap_fail;
+
+ spacemit_obj->vaddr = vaddr;
+
+vmap_success:
+ spacemit_obj->vmap_cnt++;
+ iosys_map_set_vaddr(map, vaddr);
+ mutex_unlock(&spacemit_obj->vmap_lock);
+ return ret;
+
+vmap_fail:
+ mutex_unlock(&spacemit_obj->vmap_lock);
+ return -ENOMEM;
+}
+
+void spacemit_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map)
+{
+ struct spacemit_gem_object *spacemit_obj = to_spacemit_obj(obj);
+
+ mutex_lock(&spacemit_obj->vmap_lock);
+ spacemit_obj->vmap_cnt--;
+ if (!spacemit_obj->vmap_cnt) {
+ vunmap(map->vaddr);
+ spacemit_obj->vaddr = NULL;
+ }
+ mutex_unlock(&spacemit_obj->vmap_lock);
+}
+
+const struct vm_operations_struct vm_ops = {
+ .open = drm_gem_vm_open,
+ .close = drm_gem_vm_close,
+};
+
+static const struct drm_gem_object_funcs spacemit_gem_funcs = {
+ .free = spacemit_gem_free_object,
+ .get_sg_table = spacemit_gem_prime_get_sg_table,
+ .vmap = spacemit_gem_prime_vmap,
+ .vunmap = spacemit_gem_prime_vunmap,
+ .vm_ops = &vm_ops
+};
+
+static struct drm_gem_object *
+__spacemit_gem_create_object(struct drm_device *drm, size_t size)
+{
+ struct spacemit_gem_object *spacemit_obj;
+ struct drm_gem_object *gem_obj;
+ int ret;
+
+ spacemit_obj = kzalloc(sizeof(*spacemit_obj), GFP_KERNEL);
+ if (!spacemit_obj)
+ return ERR_PTR(-ENOMEM);
+
+ gem_obj = &spacemit_obj->base;
+
+ gem_obj->funcs = &spacemit_gem_funcs;
+
+ drm_gem_private_object_init(drm, gem_obj, size);
+
+ ret = drm_gem_create_mmap_offset(gem_obj);
+ if (ret) {
+ drm_gem_object_release(gem_obj);
+ kfree(spacemit_obj);
+ return ERR_PTR(ret);
+ }
+
+ spacemit_obj->sgt = NULL;
+ spacemit_obj->vaddr = NULL;
+ spacemit_obj->vmap_cnt = 0;
+ mutex_init(&spacemit_obj->vmap_lock);
+
+ return gem_obj;
+}
+
+static struct drm_gem_object *
+spacemit_gem_create_object(struct drm_device *drm, size_t size)
+{
+ struct spacemit_gem_object *spacemit_obj;
+ struct drm_gem_object *gem_obj;
+ int ret;
+
+ size = PAGE_ALIGN(size);
+
+ gem_obj = __spacemit_gem_create_object(drm, size);
+ if (IS_ERR(gem_obj))
+ return gem_obj;
+
+ spacemit_obj = to_spacemit_obj(gem_obj);
+ ret = spacemit_gem_alloc_buf(drm, spacemit_obj, size);
+ if (ret) {
+ drm_gem_object_put(gem_obj);
+ return ERR_PTR(ret);
+ }
+
+ return gem_obj;
+}
+
+static struct drm_gem_object *
+spacemit_gem_create_with_handle(struct drm_file *file_priv, struct drm_device *drm,
+ size_t size, unsigned int *handle)
+{
+ struct drm_gem_object *gem_obj;
+ int ret;
+
+ gem_obj = spacemit_gem_create_object(drm, size);
+ if (IS_ERR(gem_obj))
+ return gem_obj;
+
+ ret = drm_gem_handle_create(file_priv, gem_obj, handle);
+ drm_gem_object_put(gem_obj);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return gem_obj;
+}
+
+int spacemit_gem_dumb_create(struct drm_file *file_priv,
+ struct drm_device *drm,
+ struct drm_mode_create_dumb *args)
+{
+ struct drm_gem_object *gem_obj;
+
+ args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
+ args->size = args->pitch * args->height;
+
+ gem_obj = spacemit_gem_create_with_handle(file_priv, drm, args->size, &args->handle);
+
+ return PTR_ERR_OR_ZERO(gem_obj);
+}
+
+static int spacemit_gem_object_mmap(struct drm_gem_object *gem_obj,
+ struct vm_area_struct *vma)
+{
+ struct spacemit_gem_object *spacemit_obj = to_spacemit_obj(gem_obj);
+ unsigned long addr = vma->vm_start;
+ struct sg_page_iter piter;
+ int ret;
+
+ for_each_sgtable_page(spacemit_obj->sgt, &piter, vma->vm_pgoff) {
+ struct page *page = sg_page_iter_page(&piter);
+
+ ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE,
+ vma->vm_page_prot);
+ if (ret)
+ return ret;
+
+ addr += PAGE_SIZE;
+ if (addr >= vma->vm_end)
+ return 0;
+ }
+
+ return 0;
+}
+
+int spacemit_gem_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct drm_gem_object *gem_obj;
+ int ret;
+
+ ret = drm_gem_mmap(filp, vma);
+ if (ret)
+ return ret;
+
+ gem_obj = vma->vm_private_data;
+
+ vma->vm_pgoff -= drm_vma_node_start(&gem_obj->vma_node);
+
+ if (gem_obj->import_attach) {
+ drm_gem_object_put(gem_obj);
+ vma->vm_private_data = NULL;
+
+ return dma_buf_mmap(gem_obj->dma_buf, vma, vma->vm_pgoff);
+ }
+
+ return spacemit_gem_object_mmap(gem_obj, vma);
+}
+
+struct drm_gem_object *
+spacemit_gem_prime_import_sg_table(struct drm_device *drm,
+ struct dma_buf_attachment *attach,
+ struct sg_table *sgt)
+{
+ struct spacemit_gem_object *spacemit_obj;
+ struct drm_gem_object *gem_obj;
+ size_t size = PAGE_ALIGN(attach->dmabuf->size);
+
+ gem_obj = __spacemit_gem_create_object(drm, size);
+ if (IS_ERR(gem_obj))
+ return gem_obj;
+
+ spacemit_obj = to_spacemit_obj(gem_obj);
+ spacemit_obj->sgt = sgt;
+
+ return gem_obj;
+}
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_GEM_H_
+#define _SPACEMIT_GEM_H_
+
+#include <linux/scatterlist.h>
+#include <drm/drm_device.h>
+#include <drm/drm_gem.h>
+#include "spacemit_dmmu.h"
+
+struct spacemit_gem_object {
+ struct drm_gem_object base;
+ struct sg_table *sgt;
+ void *vaddr;
+ int vmap_cnt;
+ struct mutex vmap_lock;
+ struct list_head ttb_entry;
+};
+
+static inline struct spacemit_gem_object *
+to_spacemit_obj(struct drm_gem_object *gem_obj)
+{
+ return container_of(gem_obj, struct spacemit_gem_object, base);
+}
+
+struct drm_gem_object *
+spacemit_gem_prime_import_sg_table(struct drm_device *drm, struct dma_buf_attachment *attch,
+ struct sg_table *sgt);
+int spacemit_gem_dumb_create(struct drm_file *file_priv, struct drm_device *drm,
+ struct drm_mode_create_dumb *args);
+int spacemit_gem_mmap(struct file *filp, struct vm_area_struct *vma);
+
+#endif /* _SPACEMIT_GEM_H_ */
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/hdmi.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_device.h>
+#include <linux/component.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "spacemit_hdmi.h"
+#include "spacemit_lib.h"
+#include "spacemit_dpu.h"
+
+#define SPACEMIT_HDMI_DDC_OTHER_MASK BIT(31)
+#define SPACEMIT_HDMI_DDC_DONE_MASK BIT(30)
+#define SPACEMIT_HDMI_HPD_IQR_MASK BIT(29)
+
+#define SPACEMIT_HDMI_DDC_NACK BIT(15)
+#define SPACEMIT_HDMI_DDC_DONE BIT(14)
+#define SPACEMIT_HDMI_HPD_IQR BIT(13)
+
+#define SPACEMIT_HDMI_HPD_STATUS BIT(12)
+
+#define SPACEMIT_HDMI_PHY_STATUS 0xC
+
+
+struct hdmi_data_info {
+ uint8_t edid[256];
+ int vic;
+ bool sink_has_audio;
+ unsigned int enc_in_format;
+ unsigned int enc_out_format;
+ unsigned int colorimetry;
+};
+
+struct spacemit_hdmi_i2c {
+ u8 segment_addr;
+
+ struct mutex lock;
+ struct completion cmp;
+};
+
+struct spacemit_hdmi {
+ struct device *dev;
+ struct drm_device *drm_dev;
+
+ int irq;
+ struct clk *pclk;
+ void __iomem *regs;
+
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+
+ struct reset_control *hdmi_reset;
+ struct clk *hdmi_mclk;
+
+ unsigned int tmds_rate;
+
+ bool edid_done;
+ bool use_no_edid;
+ struct hdmi_data_info *hdmi_data;
+ struct drm_display_mode previous_mode;
+};
+
+#define encoder_to_spacemit_hdmi(encoder) \
+ container_of(encoder, struct spacemit_hdmi, encoder)
+
+#define connector_to_spacemit_hdmi(connector) \
+ container_of(connector, struct spacemit_hdmi, connector)
+
+static inline u32 hdmi_readb(struct spacemit_hdmi *hdmi, u16 offset)
+{
+ return readl_relaxed(hdmi->regs + (offset));
+}
+
+static inline void hdmi_writeb(struct spacemit_hdmi *hdmi, u16 offset, u32 val)
+{
+ writel_relaxed(val, hdmi->regs + (offset));
+}
+
+static int hdmi_get_plug_in_status(struct spacemit_hdmi *hdmi)
+{
+ u32 value;
+ value = readl_relaxed(hdmi->regs + SPACEMIT_HDMI_PHY_STATUS) & SPACEMIT_HDMI_HPD_STATUS;
+
+ return !!value;
+}
+
+static void spacemit_hdmi_set_pwr_mode(struct spacemit_hdmi *hdmi, int mode)
+{
+ //normal/ low power
+}
+
+static void spacemit_hdmi_reset(struct spacemit_hdmi *hdmi)
+{
+}
+
+static int spacemit_hdmi_config_video_vsi(struct spacemit_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ union hdmi_infoframe frame;
+ int rc;
+
+ rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
+ &hdmi->connector,
+ mode);
+
+ return 0;
+}
+
+static int spacemit_hdmi_upload_frame(struct spacemit_hdmi *hdmi, int setup_rc,
+ union hdmi_infoframe *frame, u32 frame_index,
+ u32 mask, u32 disable, u32 enable)
+{
+ if (setup_rc >= 0) {
+ u8 packed_frame[0x11];
+ ssize_t rc;
+
+ rc = hdmi_infoframe_pack(frame, packed_frame,
+ sizeof(packed_frame));
+ if (rc < 0)
+ return rc;
+ }
+
+ return setup_rc;
+}
+
+static int spacemit_hdmi_config_video_avi(struct spacemit_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ union hdmi_infoframe frame;
+ int rc;
+
+ rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
+ &hdmi->connector,
+ mode);
+
+ if (hdmi->hdmi_data->enc_out_format == HDMI_COLORSPACE_YUV444)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
+ else if (hdmi->hdmi_data->enc_out_format == HDMI_COLORSPACE_YUV422)
+ frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
+ else
+ frame.avi.colorspace = HDMI_COLORSPACE_RGB;
+
+ return spacemit_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
+}
+
+static int spacemit_hdmi_config_video_timing(struct spacemit_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ return 0;
+}
+
+enum bit_depth{
+ EIGHT_BPP = 0,
+ TEN_BPP = 1,
+ TWELVE_BPP =2,
+};
+
+int power_of_two(int n) {
+ int result = 1;
+ for (int i = 0; i < n; ++i) {
+ result <<= 1;
+ }
+
+ return result;
+}
+
+int pll8_bit_5_6 (int bit_clock, int n){
+ int ret = 0;
+ bit_clock = bit_clock / n;
+
+ if (bit_clock < 425)
+ ret = 3;
+ else if (bit_clock < 850)
+ ret = 2;
+ else if (bit_clock < 1700)
+ ret = 1;
+ else
+ ret = 0;
+
+ return ret;
+}
+
+int pll6_bit_4_5 (int bit_clock, int n){
+ int ret = 0;
+ bit_clock = bit_clock / n;
+
+ if (bit_clock <= 337)
+ ret = 0;
+ else if (bit_clock < 425)
+ ret = 1;
+ else if (bit_clock < 675)
+ ret = 0;
+ else if (bit_clock < 850)
+ ret = 1;
+ else if (bit_clock < 1350)
+ ret = 0;
+ else if (bit_clock < 1700)
+ ret = 1;
+ else
+ ret = 0;
+
+ return ret;
+}
+
+int pll5_bit_0_2 (int bit_clock, int n){
+ int value = bit_clock * power_of_two(pll8_bit_5_6(bit_clock, n)) / n;
+ int ret;
+
+ if (value < 1830)
+ ret = 0;
+ else if (value < 2030)
+ ret = 1;
+ else if (value < 2275)
+ ret = 2;
+ else if (value < 2520)
+ ret = 3;
+ else if (value < 2765)
+ ret = 4;
+ else if (value < 3015)
+ ret = 5;
+ else if (value < 3260)
+ ret = 6;
+ else
+ ret = 7;
+
+ return ret;
+}
+
+int PLL9_BIT0_1[3] = {0x0, 0x1, 0x2};
+
+void pll_reg_cal(int bit_clock, int ref_clock, int n, int *integer_part, u32 *hmdi_e8_reg) {
+ long long int_para = 1000000000;
+ long long value = (power_of_two(pll8_bit_5_6(bit_clock, n))) * bit_clock * int_para / (n * (pll6_bit_4_5(bit_clock, n) + 1) * ref_clock);
+ long long integer = (power_of_two(pll8_bit_5_6(bit_clock, n)))* bit_clock / (n * (pll6_bit_4_5(bit_clock, n) + 1) * ref_clock) * int_para;
+ long long fraction = value - integer;
+ bool negative = false;
+ int bit = 0;
+ int frac_20bit = 0;
+ int pll2_reg = 0;
+ int pll1_reg = 0;
+ int pll0_reg = 0;
+
+ negative = fraction > 500000000 ? true : false;
+ fraction = negative ? 1000000000 - fraction : fraction;
+ *integer_part = negative ? integer/int_para + 1 : integer/int_para;
+
+
+ for (int i = 0; i < 20; i++){
+ if (bit >= int_para) {
+ frac_20bit |= 1 << (19 - i);
+ fraction -= int_para;
+ }
+ fraction *= 2;
+ bit = fraction;
+ }
+
+ if (!negative){
+ pll2_reg = ((frac_20bit & 0xF0000) >> 16) | (1 << 5);
+ } else {
+ frac_20bit = (~frac_20bit + 1) & 0xfffff;
+ pll2_reg = 0x10 | ((frac_20bit & 0xF0000) >> 16) | (1 << 5);
+ }
+
+ pll1_reg = (frac_20bit & 0xFF00) >> 8;
+ pll0_reg = frac_20bit & 0xFF;
+ *hmdi_e8_reg = (0x20 << 24) | (pll2_reg << 16) | (pll1_reg << 8) | pll0_reg;
+}
+
+int pll_reg (struct spacemit_hdmi *hdmi, int pixel_clock, int bit_depth) {
+ int pll9_reg = 0, pll8_reg = 0, pll7_reg = 0, pll6_reg = 0, pll5_reg = 0, pll4_reg = 0;
+ int n = 100;
+ int ref_clock = 24;
+ int hdmi_ec_reg = 0;
+ int hdmi_f0_reg = 0;
+ int hdmi_e8_reg = 0;
+ int pow = 0;
+ int bit_clock = bit_depth == EIGHT_BPP ? pixel_clock : pixel_clock * 125 / 100;
+
+ int integer_part = 0;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ pll_reg_cal(bit_clock, ref_clock, n, &integer_part, &hdmi_e8_reg);
+
+ pll9_reg = 2 << 2 | PLL9_BIT0_1[bit_depth];
+ pll8_reg = (0 << 7) | (pll8_bit_5_6(bit_clock, n) << 5) | 1;
+ pll7_reg = 0x50;
+ pll6_reg = 0xD | (pll6_bit_4_5(bit_clock, n) << 4) | (2 << 6);
+ pll5_reg = 0x40 | pll5_bit_0_2(bit_clock, n);
+
+ pow = (pll8_bit_5_6(bit_clock, n));
+
+ pll4_reg = integer_part;
+
+ hdmi_ec_reg = (pll7_reg << 24) | (pll6_reg << 16) | (pll5_reg << 8) | pll4_reg;
+ hdmi_f0_reg = (pll9_reg << 8) | pll8_reg;
+
+ writel(hdmi_e8_reg, hdmi->regs + 0xe8);
+ DRM_DEBUG("%s() hdmi 0xe8 0x%x\n", __func__, hdmi_e8_reg);
+
+ writel(hdmi_ec_reg, hdmi->regs + 0xec);
+ DRM_DEBUG("%s() hdmi 0xec 0x%x\n", __func__, hdmi_ec_reg);
+
+ writel(hdmi_f0_reg, hdmi->regs + 0xf0);
+ DRM_DEBUG("%s() hdmi 0xf0 0x%x\n", __func__, hdmi_f0_reg);
+
+ return 0;
+}
+
+static void hdmi_i2c_timing(struct spacemit_hdmi *hdmi)
+{
+ uint32_t reg = 0;
+ uint32_t apb_clk = 153500*1000;/*Hz*/
+ uint32_t apb_time = 1000*1000*1000 / apb_clk; /*ns*/
+ uint32_t i2c_clk = 100*1000; /*Hz*/
+ uint32_t i2c_time = 1000*1000*1000 / i2c_clk; /*ns*/
+ uint32_t scl_high_time, scl_low_time; /*ns*/
+ uint32_t scl_high_count = 0, scl_low_count = 0;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ reg = hdmi_readb(hdmi, 0x18);
+ DRM_DEBUG("%s() hdmi 0x18 #1 0x%x\n", __func__, reg);
+
+ scl_high_time = i2c_time / 2;
+ scl_low_time = i2c_time / 2;
+ scl_high_count = scl_high_time / apb_time;
+ scl_low_count = scl_low_time / apb_time;
+
+ scl_high_count = (scl_high_count - 3) >> 2;
+ scl_low_count = (scl_low_count - 3) >> 2;
+
+ reg &= ~0x7FFFF;
+ reg |= (5 << 16); /*glitch*/
+ reg |= scl_high_count << 8; /*high. time = value *4 + 3*/
+ reg |= scl_low_count; /*low. time = value *4 +3*/
+ DRM_DEBUG("%s() scl_high_count %d, scl_low_count %d\n", __func__, scl_high_count, scl_low_count);
+
+ hdmi_writeb(hdmi, 0x18, reg);
+ msleep(2);
+ reg = hdmi_readb(hdmi, 0x18);
+ DRM_DEBUG("%s() hdmi 0x18 #2 0x%x\n", __func__, reg);
+}
+
+static void hdmi_i2c_read(struct spacemit_hdmi *hdmi, uint8_t addr, uint8_t* message, uint32_t length)
+{
+ int i, count = 0, left = length;
+ uint8_t *pvalue = message;
+ uint32_t value;
+ uint32_t reg, num;
+ int timeout = 1000;
+
+ DRM_DEBUG("hdmi_i2c_read ++%u\r\n", length);
+
+ do{
+ if(left <= 16)
+ count = left;
+ else
+ count = 16;
+ left -= count;
+
+ value = ((count-1) << 8) + (addr << 1) + 1;
+ hdmi_writeb(hdmi, 0x8, value & 0xFFFF);
+
+ reg = hdmi_readb(hdmi, 0xC);
+ num = (reg & 0x1f0) >> 4;
+
+ while(num < count){
+ reg = hdmi_readb(hdmi, 0xC);
+ num = (reg & 0x1f0) >> 4;
+ }
+
+ for(i = 0; i < count; i++){
+ value = hdmi_readb(hdmi, 0x4);
+ *pvalue++ = value;
+ }
+ } while(left > 0);
+
+ while(timeout) {
+ if ((hdmi_readb(hdmi, 0xc) & BIT(14)) != 0)
+ break;
+
+ udelay(100);
+ timeout--;
+ };
+
+ if (timeout == 0)
+ DRM_INFO("%s wait hdmi ddc command done timeout\n", __func__);
+
+ value = hdmi_readb(hdmi, 0xc);
+ DRM_DEBUG("%s hdmi status 0x%x\n", __func__, value);
+ value |= SPACEMIT_HDMI_DDC_DONE;
+
+ hdmi_writeb(hdmi, 0xc, value);
+ udelay(100);
+
+ DRM_DEBUG("hdmi_i2c_read --%u\r\n", length);
+
+ return;
+}
+
+static int hdmi_i2c_write(struct spacemit_hdmi *hdmi, uint8_t addr, uint8_t* message, uint32_t length)
+{
+ int i, count = 0, left = length;
+ uint8_t *pvalue = message;
+ uint32_t value, reg;
+ int timeout = 1000;
+
+ DRM_DEBUG("hdmi_i2c_write ++ %u\r\n", length);
+
+ do{
+ if(left <= 16)
+ count = left;
+ else
+ count = 16;
+ left -= count;
+
+ for(i = 0; i < count; i++){
+ value = *pvalue++;
+ hdmi_writeb(hdmi, 0x0, value & 0xFF);
+ }
+ value = ((count-1) << 8) + (addr << 1);
+
+ hdmi_writeb(hdmi, 0x8, value & 0xFFFF);
+ reg = hdmi_readb(hdmi, 0x0C);
+
+ if (reg & BIT(16)) {
+ DRM_INFO("hdmi_i2c_write i2c ARB FAIL!!");
+ return -1;
+ }
+ } while(left > 0);
+
+ while(timeout) {
+ if ((hdmi_readb(hdmi, 0x0C) & BIT(14)) != 0)
+ break;
+
+ udelay(100);
+ timeout--;
+ };
+
+ if (timeout == 0) {
+ DRM_INFO("%s wait hdmi ddc command done timeout\n", __func__);
+ return -1;
+ }
+ udelay(100);
+
+ DRM_DEBUG("hdmi_i2c_write --%u\r\n", length);
+
+ return 0;
+
+}
+
+int edid_read (struct spacemit_hdmi *hdmi){
+ int i;
+ struct hdmi_data_info *hdmi_data = hdmi->hdmi_data;
+ uint8_t offset;
+ int result;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ for(i = 0; i < 8; i++) {
+ offset = i * 16;
+ result = hdmi_i2c_write(hdmi, 0x50, &offset, 1);
+ if (result < 0)
+ break;
+ hdmi_i2c_read(hdmi, 0x50, hdmi_data->edid + offset, 16);
+ }
+
+ if (result < 0) {
+ // memset(hdmi_data->edid, 0x00, EDID_LENGTH);
+ memset(hdmi_data->edid, 0x00, 256);
+ return result;
+ }
+
+ if (hdmi_data->edid[0x7e] == 0x01) {
+ // extend edid
+ for(i = 8; i < 16; i++) {
+ offset = i * 16;
+ result = hdmi_i2c_write(hdmi, 0x50, &offset, 1);
+ if (result < 0)
+ break;
+ hdmi_i2c_read(hdmi, 0x50, hdmi_data->edid + offset, 16);
+ }
+ }
+
+ for(i = 0; i < 256; i += 8){
+ DRM_DEBUG("EDID 0x%x: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\r\n", i,
+ hdmi_data->edid[i], hdmi_data->edid[i+1], hdmi_data->edid[i+2], hdmi_data->edid[i+3],
+ hdmi_data->edid[i+4], hdmi_data->edid[i+5], hdmi_data->edid[i+6], hdmi_data->edid[i+7]);
+ }
+
+ if ((hdmi_data->edid[0] == 0x00) && (hdmi_data->edid[1] == 0xff) && (hdmi_data->edid[2] == 0xff) &&
+ (hdmi_data->edid[3] == 0xff) && (hdmi_data->edid[4] == 0xff) && (hdmi_data->edid[5] == 0xff) &&
+ (hdmi_data->edid[6] == 0xff) && (hdmi_data->edid[7] == 0x00)) {
+ hdmi->edid_done = true;
+ } else {
+ hdmi->edid_done = false;
+ }
+
+ return 0;
+}
+
+static int spacemit_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
+{
+ struct spacemit_hdmi *hdmi = data;
+ struct hdmi_data_info *hdmi_data = hdmi->hdmi_data;
+ uint32_t value;
+ int ret;
+
+ DRM_INFO("%s() len %zd\n", __func__, len);
+
+ if (len > 128)
+ return -EINVAL;
+
+ if (!hdmi->edid_done) {
+ hdmi_i2c_timing(hdmi);
+ ret = edid_read(hdmi);
+ if (ret < 0) {
+ DRM_INFO("%s() failed to read edid\n", __func__);
+ return -EINVAL;
+ }
+
+ memcpy(buf, hdmi_data->edid, len);
+
+ if (!hdmi->edid_done) {
+ value = hdmi_readb(hdmi, SPACEMIT_HDMI_PHY_STATUS);
+ DRM_INFO("%s() get edid failed, hdmi status 0x%x\n", __func__, value);
+ value |= (SPACEMIT_HDMI_DDC_DONE | SPACEMIT_HDMI_DDC_NACK);
+ hdmi_writeb(hdmi, SPACEMIT_HDMI_PHY_STATUS, value);
+ udelay(5);
+ }
+
+ } else {
+ memcpy(buf, hdmi_data->edid + EDID_LENGTH, len);
+ }
+
+ return 0;
+}
+
+void hdmi_write_bits(struct spacemit_hdmi *hdmi, u16 offset, u32 value, u32 mask, u32 shifts)
+{
+ u32 reg_val;
+
+ reg_val = readl_relaxed(hdmi->regs + (offset));
+ reg_val &= ~(mask << shifts);
+ reg_val |= (value << shifts);
+ writel_relaxed(reg_val, hdmi->regs + (offset));
+}
+
+void hdmi_init (struct spacemit_hdmi *hdmi, int pixel_clock, int bit_depth){
+ u32 value = 0;
+ int color_depth = bit_depth == EIGHT_BPP ? 4 : 5;
+
+ u32 good_phase = 0x00;
+ u32 bias_current = 0x01;
+ u32 bias_risistor = 0x07;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ writel(0xAE5C410F, hdmi->regs + 0xe0);
+ hdmi_write_bits(hdmi, 0xe0, bias_current, 0x03, 29);
+ hdmi_write_bits(hdmi, 0xe0, bias_risistor, 0x0F, 18);
+ hdmi_write_bits(hdmi, 0xe0, good_phase, 0x03, 14);
+ // writel(0xEE40410F, hdmi->regs + 0xe0);
+ // value = readl_relaxed(hdmi->regs + 0xe0);
+ // DRM_DEBUG("%s() hdmi 0xe0 0x%x\n", __func__, value);
+
+ value = 0x0000000d | (color_depth << 4);
+ writel(value, hdmi->regs + 0x34);
+ DRM_DEBUG("%s() hdmi 0x34 0x%x\n", __func__, value);
+
+ pll_reg(hdmi, pixel_clock, bit_depth);
+ writel(0x03, hdmi->regs + 0xe4);
+ value = readl_relaxed(hdmi->regs + 0xe4);
+ DRM_DEBUG("%s() hdmi pll lock status 0x%x\n", __func__, value);
+ // while ( (value & 0x10000) != 0) {
+ // value = readl_relaxed(hdmi->regs + 0xe4);
+ // }
+ udelay(100);
+
+ // value = 0x3018C000 | bit_depth;
+ value = 0x1C208000 | bit_depth;
+ writel(value, hdmi->regs + 0x28);
+ DRM_DEBUG("%s() hdmi 0x28 0x%x\n", __func__, value);
+}
+
+static int spacemit_hdmi_setup(struct spacemit_hdmi *hdmi,
+ struct drm_display_mode *mode)
+{
+ void __iomem *ciu = (void __iomem *)ioremap(0xD4282C00, 0x200);
+ struct hdmi_data_info *hdmi_data = hdmi->hdmi_data;
+ int bit_depth = EIGHT_BPP;
+ u32 value;
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ // ciu chip id
+ value = readl_relaxed(ciu);
+ if (value == 0xa08501) {
+ // default 10bpc
+ bit_depth = TEN_BPP;
+
+ // 08H, 09H: ID Manufacturer Nanme
+ // 0AH, 0BH: ID Product Code
+ if ((hdmi_data->edid[8] == 0x30) && (hdmi_data->edid[9] == 0xa3) &&
+ ((hdmi_data->edid[10] == 0x88) || (hdmi_data->edid[10] == 0x89)) && (hdmi_data->edid[11] == 0x23)) {
+ // Lecoo HU20238FB0
+ bit_depth = EIGHT_BPP;
+ } else if ((hdmi_data->edid[8] == 0x26) && (hdmi_data->edid[9] == 0x01) &&
+ (hdmi_data->edid[10] == 0x12) && (hdmi_data->edid[11] == 0x24)) {
+ // IPASON XC242-J
+ bit_depth = EIGHT_BPP;
+ } else if ((hdmi_data->edid[8] == 0x05) && (hdmi_data->edid[9] == 0xe3) &&
+ (hdmi_data->edid[10] == 0x90) && (hdmi_data->edid[11] == 0x24)) {
+ // AOC Q2490W1
+ bit_depth = EIGHT_BPP;
+ }
+ }
+
+ if (bit_depth == EIGHT_BPP) {
+ DRM_INFO("%s() id 0x%x, hdmi 8bpc \n", __func__, value);
+ } else if (bit_depth == TEN_BPP) {
+ DRM_INFO("%s() id 0x%x, hdmi 10bpc \n", __func__, value);
+ }
+
+ hdmi_init(hdmi, hdmi->previous_mode.clock, bit_depth);
+
+ spacemit_hdmi_config_video_timing(hdmi, mode);
+ spacemit_hdmi_config_video_avi(hdmi, mode);
+ spacemit_hdmi_config_video_vsi(hdmi, mode);
+
+ iounmap(ciu);
+
+ return 0;
+}
+
+static void spacemit_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct spacemit_hdmi *hdmi = encoder_to_spacemit_hdmi(encoder);
+ DRM_DEBUG("%s() \n", __func__);
+
+ /* Store the display mode for plugin/DPMS poweron events */
+ drm_mode_copy(&hdmi->previous_mode, adj_mode);
+}
+
+static void spacemit_hdmi_encoder_enable(struct drm_encoder *encoder)
+{
+ struct spacemit_hdmi *hdmi = encoder_to_spacemit_hdmi(encoder);
+ DRM_INFO("%s()\n", __func__);
+
+ spacemit_hdmi_set_pwr_mode(hdmi, NORMAL);
+ spacemit_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void spacemit_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct spacemit_hdmi *hdmi = encoder_to_spacemit_hdmi(encoder);
+ struct spacemit_dpu *dpu = crtc_to_dpu(encoder->crtc);
+ DRM_INFO("%s()\n", __func__);
+
+ spacemit_dpu_stop(dpu);
+ writel(0x00, hdmi->regs + 0xe4);
+ udelay(100);
+ spacemit_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
+}
+
+static bool spacemit_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ return true;
+}
+
+static int
+spacemit_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ DRM_DEBUG("%s()\n", __func__);
+ return 0;
+}
+
+static struct drm_encoder_helper_funcs spacemit_hdmi_encoder_helper_funcs = {
+ .enable = spacemit_hdmi_encoder_enable,
+ .disable = spacemit_hdmi_encoder_disable,
+ .mode_fixup = spacemit_hdmi_encoder_mode_fixup,
+ .mode_set = spacemit_hdmi_encoder_mode_set,
+ .atomic_check = spacemit_hdmi_encoder_atomic_check,
+};
+
+static enum drm_connector_status
+spacemit_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct spacemit_hdmi *hdmi = connector_to_spacemit_hdmi(connector);
+ int ret;
+ enum drm_connector_status status;
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ ret = pm_runtime_get_sync(hdmi->dev);
+ if (ret < 0) {
+ DRM_INFO("%s() pm_runtime_get_sync failed\n", __func__);
+ return connector_status_connected;
+ }
+
+ if (hdmi_get_plug_in_status(hdmi)) {
+ DRM_INFO("%s() hdmi status connected\n", __func__);
+ status = connector_status_connected;
+
+ } else {
+ DRM_INFO("%s() hdmi status disconnected\n", __func__);
+ status = connector_status_disconnected;
+ }
+
+ pm_runtime_put(hdmi->dev);
+
+ return status;
+}
+
+static int spacemit_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+ struct spacemit_hdmi *hdmi = connector_to_spacemit_hdmi(connector);
+ int ret;
+ struct edid *edid;
+ uint32_t value;
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ if (hdmi->use_no_edid)
+ return drm_add_modes_noedid(connector, 1920, 1080);
+
+ value = hdmi_readb(hdmi, SPACEMIT_HDMI_PHY_STATUS);
+ DRM_DEBUG("%s() hdmi status 0x%x\n", __func__, value);
+ value &= ~(SPACEMIT_HDMI_DDC_OTHER_MASK | SPACEMIT_HDMI_DDC_DONE_MASK);
+ value |= (SPACEMIT_HDMI_HPD_IQR | SPACEMIT_HDMI_DDC_DONE | SPACEMIT_HDMI_DDC_NACK);
+ hdmi_writeb(hdmi, SPACEMIT_HDMI_PHY_STATUS, value);
+ udelay(5);
+
+ hdmi->edid_done = false;
+
+ edid = drm_do_get_edid(connector, spacemit_hdmi_get_edid_block, hdmi);
+ if (edid) {
+ if (hdmi->edid_done) {
+ drm_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ } else {
+ ret = drm_add_modes_noedid(connector, 1920, 1080);
+ }
+ kfree(edid);
+ } else {
+ DRM_INFO("%s() get edid failed\n", __func__);
+ ret = drm_add_modes_noedid(connector, 1920, 1080);
+ }
+
+ return ret;
+}
+
+static enum drm_mode_status
+spacemit_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static int
+spacemit_hdmi_probe_single_connector_modes(struct drm_connector *connector,
+ uint32_t maxX, uint32_t maxY)
+{
+ return drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+}
+
+static void spacemit_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ struct spacemit_hdmi *hdmi = connector_to_spacemit_hdmi(connector);
+ kfree(hdmi->hdmi_data);
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs spacemit_hdmi_connector_funcs = {
+ .fill_modes = spacemit_hdmi_probe_single_connector_modes,
+ .detect = spacemit_hdmi_connector_detect,
+ .destroy = spacemit_hdmi_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static struct drm_connector_helper_funcs spacemit_hdmi_connector_helper_funcs = {
+ .get_modes = spacemit_hdmi_connector_get_modes,
+ .mode_valid = spacemit_hdmi_connector_mode_valid,
+};
+
+static int spacemit_hdmi_register(struct drm_device *drm, struct spacemit_hdmi *hdmi)
+{
+ struct drm_encoder *encoder = &hdmi->encoder;
+ struct device *dev = hdmi->dev;
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ drm_encoder_helper_add(encoder, &spacemit_hdmi_encoder_helper_funcs);
+ drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS);
+
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_helper_add(&hdmi->connector,
+ &spacemit_hdmi_connector_helper_funcs);
+
+ drm_connector_init(drm, &hdmi->connector,
+ &spacemit_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+
+ drm_connector_attach_encoder(&hdmi->connector, encoder);
+
+ return 0;
+}
+
+static irqreturn_t spacemit_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct spacemit_hdmi *hdmi = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ uint32_t value;
+
+ value = hdmi_readb(hdmi, SPACEMIT_HDMI_PHY_STATUS);
+ if (value & SPACEMIT_HDMI_HPD_IQR) {
+ value |= SPACEMIT_HDMI_HPD_IQR;
+ hdmi_writeb(hdmi, 0xc, value);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ return ret;
+}
+
+static irqreturn_t spacemit_hdmi_irq(int irq, void *dev_id)
+{
+ struct spacemit_hdmi *hdmi = dev_id;
+ hdmi->edid_done = false;
+
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
+
+ return IRQ_HANDLED;
+}
+
+static int spacemit_hdmi_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = data;
+ struct spacemit_hdmi *hdmi;
+ int irq;
+ int ret;
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->hdmi_data = devm_kzalloc(dev, sizeof(*(hdmi->hdmi_data)), GFP_KERNEL);
+ if (!hdmi->hdmi_data)
+ return -ENOMEM;
+
+ hdmi->dev = dev;
+ hdmi->drm_dev = drm;
+
+ hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
+
+ if (of_property_read_bool(dev->of_node, "use-no-edid"))
+ hdmi->use_no_edid = true;
+ else
+ hdmi->use_no_edid = false;
+
+ hdmi->hdmi_reset = devm_reset_control_get_optional_shared(&pdev->dev, "hdmi_reset");
+ if (IS_ERR_OR_NULL(hdmi->hdmi_reset)) {
+ DRM_INFO("Failed to found hdmi_reset\n");
+ }
+
+ hdmi->hdmi_mclk = of_clk_get_by_name(dev->of_node, "hmclk");
+ if (IS_ERR(hdmi->hdmi_mclk)) {
+ DRM_INFO("Failed to found hdmi mclk\n");
+ }
+
+ dev_set_drvdata(dev, hdmi);
+
+ pm_runtime_enable(&pdev->dev);
+
+ if (!IS_ERR_OR_NULL(hdmi->hdmi_reset)) {
+ ret = reset_control_deassert(hdmi->hdmi_reset);
+ if (ret < 0) {
+ DRM_INFO("Failed to deassert hdmi_reset\n");
+ }
+ }
+
+ pm_runtime_get_sync(&pdev->dev);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ DRM_ERROR("%s() get hdmi phd irq failed\n", __func__);
+ return -ENOENT;
+ }
+ DRM_DEBUG("%s() hdmi hpd irq %d\n", __func__, irq);
+
+ spacemit_hdmi_reset(hdmi);
+ hdmi->edid_done = false;
+
+ ret = spacemit_hdmi_register(drm, hdmi);
+
+ ret = devm_request_threaded_irq(dev, irq, spacemit_hdmi_hardirq,
+ spacemit_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
+ if (ret < 0)
+ goto irq_err;
+
+ return 0;
+
+irq_err:
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
+
+ return ret;
+}
+
+static void spacemit_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct spacemit_hdmi *hdmi = dev_get_drvdata(dev);
+ int ret;
+
+ DRM_DEBUG("%s() \n", __func__);
+
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder.funcs->destroy(&hdmi->encoder);
+
+ pm_runtime_put_sync(&pdev->dev);
+ if (!IS_ERR_OR_NULL(hdmi->hdmi_reset)) {
+ ret = reset_control_assert(hdmi->hdmi_reset);
+ if (ret < 0) {
+ DRM_INFO("Failed to assert hdmi_reset\n");
+ }
+ }
+ pm_runtime_disable(dev);
+}
+
+static const struct component_ops spacemit_hdmi_ops = {
+ .bind = spacemit_hdmi_bind,
+ .unbind = spacemit_hdmi_unbind,
+};
+
+static int spacemit_hdmi_probe(struct platform_device *pdev)
+{
+ DRM_DEBUG("%s() \n", __func__);
+
+ return component_add(&pdev->dev, &spacemit_hdmi_ops);
+}
+
+static int spacemit_hdmi_remove(struct platform_device *pdev)
+{
+ DRM_DEBUG("%s() \n", __func__);
+
+ component_del(&pdev->dev, &spacemit_hdmi_ops);
+
+ return 0;
+}
+
+static int hdmi_rt_pm_resume(struct device *dev)
+{
+ struct spacemit_hdmi *hdmi = dev_get_drvdata(dev);
+ uint64_t clk_val;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ clk_prepare_enable(hdmi->hdmi_mclk);
+
+ clk_val = clk_get_rate(hdmi->hdmi_mclk);
+ DRM_DEBUG("get hdmi mclk=%lld\n", clk_val);
+ if(clk_val != DPU_MCLK_DEFAULT){
+ clk_val = clk_round_rate(hdmi->hdmi_mclk, DPU_MCLK_DEFAULT);
+ clk_set_rate(hdmi->hdmi_mclk, clk_val);
+ DRM_INFO("set hdmi mclk=%lld\n", clk_val);
+ }
+
+ return 0;
+}
+
+static int hdmi_rt_pm_suspend(struct device *dev)
+{
+ struct spacemit_hdmi *hdmi = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ clk_disable_unprepare(hdmi->hdmi_mclk);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int hdmi_drv_pm_suspend(struct device *dev)
+{
+ struct spacemit_hdmi *hdmi = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ clk_disable_unprepare(hdmi->hdmi_mclk);
+
+ return 0;
+}
+
+static int hdmi_drv_pm_resume(struct device *dev)
+{
+ struct spacemit_hdmi *hdmi = dev_get_drvdata(dev);
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ clk_prepare_enable(hdmi->hdmi_mclk);
+
+ return 0;
+}
+
+#endif
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+ SET_RUNTIME_PM_OPS(hdmi_rt_pm_suspend,
+ hdmi_rt_pm_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(hdmi_drv_pm_suspend,
+ hdmi_drv_pm_resume)
+};
+
+static const struct of_device_id spacemit_hdmi_dt_ids[] = {
+ { .compatible = "spacemit,hdmi",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, spacemit_hdmi_dt_ids);
+
+struct platform_driver spacemit_hdmi_driver = {
+ .probe = spacemit_hdmi_probe,
+ .remove = spacemit_hdmi_remove,
+ .driver = {
+ .name = "spacemit-hdmi-drv",
+ .of_match_table = spacemit_hdmi_dt_ids,
+ .pm = &hdmi_pm_ops,
+ },
+};
+
+// module_platform_driver(spacemit_hdmi_driver);
+
+static int spacemit_hdmi_driver_init(void)
+{
+ return platform_driver_register(&spacemit_hdmi_driver);
+}
+late_initcall_sync(spacemit_hdmi_driver_init);
+
+MODULE_DESCRIPTION("Spacemit HDMI Driver");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+enum {
+ INFOFRAME_VSI = 0x05,
+ INFOFRAME_AVI = 0x06,
+ INFOFRAME_AAI = 0x08,
+};
+
+enum PWR_MODE {
+ NORMAL,
+ LOWER_PWR,
+};
+
+enum {
+ HDMI_TIMING_640_480P_60 = 0,
+ HDMI_TIMING_720_480P_60 = 1,
+ HDMI_TIMING_720_576P_50 = 2,
+ HDMI_TIMING_1280_720P_30 = 3,
+ HDMI_TIMING_1280_720P_50 = 4,
+ HDMI_TIMING_1920_1080P_24 = 5,
+ HDMI_TIMING_1920_1080P_60 = 6,
+ HDMI_TIMING_MAX
+};
+
+enum {
+ HDMI_SYNC_POL_POS,
+ HDMI_SYNC_POL_NEG,
+};
+
+struct hdmi_timing
+{
+ unsigned short hfp;
+ unsigned short hbp;
+ unsigned short hsync;
+ unsigned short hact;
+
+ unsigned short vfp;
+ unsigned short vbp;
+ unsigned short vsync;
+ unsigned short vact;
+
+ unsigned short vic;
+ unsigned short hpol;
+ unsigned short vpol;
+ unsigned short reserved;
+};
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include "spacemit_lib.h"
+
+struct bmp_header {
+ u16 magic;
+ u32 size;
+ u32 unused;
+ u32 start;
+} __attribute__((__packed__));
+
+struct dib_header {
+ u32 size;
+ u32 width;
+ u32 height;
+ u16 planes;
+ u16 bpp;
+ u32 compression;
+ u32 data_size;
+ u32 h_res;
+ u32 v_res;
+ u32 colours;
+ u32 important_colours;
+ u32 red_mask;
+ u32 green_mask;
+ u32 blue_mask;
+ u32 alpha_mask;
+ u32 colour_space;
+ u32 unused[12];
+} __attribute__((__packed__));
+
+int str_to_u32_array(const char *p, u32 base, u32 array[])
+{
+ const char *start = p;
+ char str[12];
+ int length = 0;
+ int i, ret;
+
+ pr_info("input: %s", p);
+
+ for (i = 0 ; i < 255; i++) {
+ while (*p == ' ')
+ p++;
+ if (*p == '\0')
+ break;
+ start = p;
+
+ while ((*p != ' ') && (*p != '\0'))
+ p++;
+
+ if ((p - start) >= sizeof(str))
+ break;
+
+ memset(str, 0, sizeof(str));
+ memcpy(str, start, p - start);
+
+ ret = kstrtou32(str, base, &array[i]);
+ if (ret) {
+ DRM_ERROR("input format error\n");
+ break;
+ }
+
+ length++;
+ }
+
+ return length;
+}
+EXPORT_SYMBOL_GPL(str_to_u32_array);
+
+int str_to_u8_array(const char *p, u32 base, u8 array[])
+{
+ const char *start = p;
+ char str[12];
+ int length = 0;
+ int i, ret;
+
+ pr_info("input: %s", p);
+
+ for (i = 0 ; i < 255; i++) {
+ while (*p == ' ')
+ p++;
+ if (*p == '\0')
+ break;
+ start = p;
+
+ while ((*p != ' ') && (*p != '\0'))
+ p++;
+
+ if ((p - start) >= sizeof(str))
+ break;
+
+ memset(str, 0, sizeof(str));
+ memcpy(str, start, p - start);
+
+ ret = kstrtou8(str, base, &array[i]);
+ if (ret) {
+ DRM_ERROR("input format error\n");
+ break;
+ }
+
+ length++;
+ }
+
+ return length;
+}
+EXPORT_SYMBOL_GPL(str_to_u8_array);
+
+#if IS_ENABLED(CONFIG_GKI_FIX_WORKAROUND)
+static struct file *gki_filp_open(const char *filename, int flags, umode_t mode)
+{
+ return 0;
+}
+static ssize_t gki_vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
+{
+ return 0;
+}
+#endif
+
+void *disp_ops_attach(const char *str, struct list_head *head)
+{
+ struct ops_list *list;
+ const char *ver;
+
+ list_for_each_entry(list, head, head) {
+ ver = list->entry->ver;
+ if (!strcmp(str, ver))
+ return list->entry->ops;
+ }
+
+ DRM_ERROR("attach disp ops %s failed\n", str);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(disp_ops_attach);
+
+int disp_ops_register(struct ops_entry *entry, struct list_head *head)
+{
+ struct ops_list *list;
+
+ list = kzalloc(sizeof(struct ops_list), GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+
+ list->entry = entry;
+ list_add(&list->head, head);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(disp_ops_register);
+
+struct device *spacemit_disp_pipe_get_by_port(struct device *dev, int port)
+{
+ struct device_node *np = dev->of_node;
+ struct device_node *endpoint;
+ struct device_node *remote_node;
+ struct platform_device *remote_pdev;
+
+ endpoint = of_graph_get_endpoint_by_regs(np, port, 0);
+ if (!endpoint) {
+ DRM_ERROR("%s/port%d/endpoint0 was not found\n",
+ np->full_name, port);
+ return NULL;
+ }
+
+ remote_node = of_graph_get_remote_port_parent(endpoint);
+ if (!remote_node) {
+ DRM_ERROR("device node was not found by endpoint0\n");
+ return NULL;
+ }
+
+ remote_pdev = of_find_device_by_node(remote_node);
+ if (remote_pdev == NULL) {
+ DRM_ERROR("find %s platform device failed\n",
+ remote_node->full_name);
+ return NULL;
+ }
+
+ return &remote_pdev->dev;
+}
+EXPORT_SYMBOL_GPL(spacemit_disp_pipe_get_by_port);
+
+struct device *spacemit_disp_pipe_get_input(struct device *dev)
+{
+ return spacemit_disp_pipe_get_by_port(dev, 1);
+}
+EXPORT_SYMBOL_GPL(spacemit_disp_pipe_get_input);
+
+struct device *spacemit_disp_pipe_get_output(struct device *dev)
+{
+ return spacemit_disp_pipe_get_by_port(dev, 0);
+}
+EXPORT_SYMBOL_GPL(spacemit_disp_pipe_get_output);
+
+/*
+ * copy from drm opensource, change name from drm_atomic_replace_property_blob_from_id
+ * to spacemit_atomic_replace_property_blob_from_id
+ */
+int spacemit_atomic_replace_property_blob_from_id(struct drm_device *dev,
+ struct drm_property_blob **blob,
+ uint64_t blob_id,
+ ssize_t expected_size,
+ ssize_t expected_elem_size,
+ bool *replaced)
+{
+ struct drm_property_blob *new_blob = NULL;
+
+ if (blob_id != 0) {
+ new_blob = drm_property_lookup_blob(dev, blob_id);
+ if (new_blob == NULL)
+ return -EINVAL;
+
+ if (expected_size > 0 &&
+ new_blob->length != expected_size) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ if (expected_elem_size > 0 &&
+ new_blob->length % expected_elem_size != 0) {
+ drm_property_blob_put(new_blob);
+ return -EINVAL;
+ }
+ }
+
+ *replaced |= drm_property_replace_blob(blob, new_blob);
+ drm_property_blob_put(new_blob);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spacemit_atomic_replace_property_blob_from_id);
+
+MODULE_DESCRIPTION("display common API library");
+MODULE_LICENSE("GPL");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_LIB_H_
+#define _SPACEMIT_LIB_H_
+
+#include <drm/drm_print.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_mode_object.h>
+#include <linux/list.h>
+
+struct ops_entry {
+ const char *ver;
+ void *ops;
+};
+
+struct ops_list {
+ struct list_head head;
+ struct ops_entry *entry;
+};
+
+int str_to_u32_array(const char *p, u32 base, u32 array[]);
+int str_to_u8_array(const char *p, u32 base, u8 array[]);
+int dump_bmp32(const char *p, u32 width, u32 height,
+ bool bgra, const char *filename);
+
+void *disp_ops_attach(const char *str, struct list_head *head);
+int disp_ops_register(struct ops_entry *entry, struct list_head *head);
+
+struct device *spacemit_disp_pipe_get_by_port(struct device *dev, int port);
+struct device *spacemit_disp_pipe_get_input(struct device *dev);
+struct device *spacemit_disp_pipe_get_output(struct device *dev);
+int spacemit_atomic_replace_property_blob_from_id(struct drm_device *dev,
+ struct drm_property_blob **blob,
+ uint64_t blob_id,
+ ssize_t expected_size,
+ ssize_t expected_elem_size,
+ bool *replaced);
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <linux/atomic.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <video/mipi_display.h>
+#include <video/of_display_timing.h>
+#include <video/videomode.h>
+#include "spacemit_mipi_panel.h"
+#include "spacemit_dsi.h"
+#include "sysfs/sysfs_display.h"
+
+const char *lcd_name;
+
+static inline struct spacemit_panel *to_spacemit_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct spacemit_panel, base);
+}
+
+static int __maybe_unused spacemit_panel_send_cmds(struct mipi_dsi_device *dsi,
+ const void *data, int size)
+{
+ struct spacemit_panel *panel;
+ struct spacemit_dsi_cmd_desc *cmds = NULL;
+ u16 len;
+ int data_off = 0;
+ int i = 0;
+ unsigned char *tmp = NULL;
+
+ if (dsi == NULL)
+ return -EINVAL;
+
+ panel = mipi_dsi_get_drvdata(dsi);
+ cmds = devm_kzalloc(&dsi->dev, sizeof(struct spacemit_dsi_cmd_desc), GFP_KERNEL);
+ if (!cmds)
+ return -ENOMEM;
+
+ while (size > 0) {
+ cmds->cmd_type = *(unsigned char *)(data + data_off++);
+ cmds->lp = *(unsigned char *)(data + data_off++);
+ cmds->delay = *(unsigned char *)(data + data_off++);
+ cmds->length = *(unsigned char *)(data + data_off++);
+ for (i = 0; i < cmds->length; i++) {
+ tmp = (unsigned char *)data + data_off++;
+ cmds->data[i] = *(unsigned char *)tmp;
+ }
+
+ len = cmds->length;
+
+ if(cmds->lp)
+ dsi->mode_flags |= MIPI_DSI_MODE_LPM;
+ else
+ dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
+
+ if (panel->info.use_dcs)
+ mipi_dsi_dcs_write_buffer(dsi, cmds->data, len);
+ else
+ mipi_dsi_generic_write(dsi, cmds->data, len);
+
+ if (cmds->delay)
+ msleep(cmds->delay);
+ size -= (len + 4);
+ }
+
+ devm_kfree(&dsi->dev, cmds);
+
+ return 0;
+}
+
+/* drm_register_client - register a client notifier */
+int spacemit_drm_register_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&drm_notifier_list, nb);
+}
+EXPORT_SYMBOL(spacemit_drm_register_client);
+
+/* drm_unregister_client - unregister a client notifier */
+int spacemit_drm_unregister_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&drm_notifier_list, nb);
+}
+EXPORT_SYMBOL(spacemit_drm_unregister_client);
+
+/* drm_notifier_call_chain - notify clients of drm_events */
+int spacemit_drm_notifier_call_chain(unsigned long val, void *v)
+{
+ return blocking_notifier_call_chain(&drm_notifier_list, val, v);
+}
+EXPORT_SYMBOL_GPL(spacemit_drm_notifier_call_chain);
+
+
+static int spacemit_panel_unprepare(struct drm_panel *p)
+{
+ struct spacemit_panel *panel = to_spacemit_panel(p);
+
+ /* do nothing before spacemit_panel_prepare been called */
+ int blank = DRM_PANEL_BLANK_POWERDOWN;
+ struct spacemit_drm_notifier_mipi noti_blank;
+ noti_blank.blank = & blank;
+ spacemit_drm_notifier_call_chain(DRM_PANEL_EARLY_EVENT_BLANK, ¬i_blank);
+ pr_info("mipi: POWERDOWN!!\n");
+
+ if (!atomic_read(&panel->prepare_refcnt))
+ return 0;
+
+ DRM_INFO("%s()\n", __func__);
+
+ gpio_direction_output(panel->gpio_reset, 1);
+
+ if(INVALID_GPIO != panel->gpio_bl) {
+ gpio_direction_output(panel->gpio_bl, 0);
+ }
+ msleep(150);
+
+ gpio_direction_output(panel->gpio_dc[0], 0);
+ gpio_direction_output(panel->gpio_dc[1], 0);
+
+ if(INVALID_GPIO != panel->gpio_avdd[0]) {
+ gpio_direction_output(panel->gpio_avdd[0], 0);
+ }
+ if(INVALID_GPIO != panel->gpio_avdd[1]) {
+ gpio_direction_output(panel->gpio_avdd[1], 0);
+ }
+
+ if (panel->vdd_1v2) {
+ regulator_disable(panel->vdd_1v2);
+ }
+ if (panel->vdd_1v8) {
+ regulator_disable(panel->vdd_1v8);
+ }
+ if (panel->vdd_2v8) {
+ regulator_disable(panel->vdd_2v8);
+ }
+
+ atomic_set(&panel->prepare_refcnt, 0);
+ return 0;
+}
+
+void spacemit_prepare_regulator (struct spacemit_panel *panel){
+ int ret = 0;
+
+ if (panel->vdd_2v8 != NULL) {
+ ret = regulator_enable(panel->vdd_2v8);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_2v8 failed\n");
+ }
+
+ if (panel->vdd_1v8 != NULL) {
+ ret = regulator_enable(panel->vdd_1v8);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_1v8 failed\n");
+ }
+
+ if (panel->vdd_1v2 != NULL) {
+ ret = regulator_enable(panel->vdd_1v2);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_1v2 failed\n");
+ }
+}
+
+static int spacemit_panel_prepare(struct drm_panel *p)
+{
+ struct spacemit_panel *panel = to_spacemit_panel(p);
+ int i = 0;
+
+ int blank_ = DRM_PANEL_BLANK_UNBLANK;
+ struct spacemit_drm_notifier_mipi noti_blank;
+
+ /* prevent this function been called twice */
+ if (atomic_read(&panel->prepare_refcnt))
+ return 0;
+
+ DRM_INFO("%s()\n", __func__);
+
+ // spacemit_prepare_regulator(panel);
+
+ gpio_direction_output(panel->gpio_dc[0], 1);
+ gpio_direction_output(panel->gpio_dc[1], 1);
+
+ if(panel->gpio_avdd[0] != INVALID_GPIO) {
+ gpio_direction_output(panel->gpio_avdd[0], 1);
+ }
+ if(panel->gpio_avdd[1] != INVALID_GPIO) {
+ gpio_direction_output(panel->gpio_avdd[1], 1);
+ }
+
+ if(panel->gpio_bl != INVALID_GPIO) {
+ gpio_direction_output(panel->gpio_bl, 1);
+ }
+
+ gpio_direction_output(panel->gpio_reset, 1);
+ for (; i < panel->reset_toggle_cnt; i++) {
+ msleep(10);
+ gpio_direction_output(panel->gpio_reset, 0);
+ msleep(10);
+ gpio_direction_output(panel->gpio_reset, 1);
+ }
+ msleep(panel->delay_after_reset);
+
+ noti_blank.blank = & blank_;
+ spacemit_drm_notifier_call_chain(DRM_PANEL_EVENT_BLANK, ¬i_blank);
+ pr_info("mipi: UNBLANK!!\n");
+
+ /* update refcnt */
+ atomic_set(&panel->prepare_refcnt, 1);
+ return 0;
+}
+
+static int spacemit_panel_disable(struct drm_panel *p)
+{
+ struct spacemit_panel *panel = to_spacemit_panel(p);
+
+ if (!atomic_read(&panel->enable_refcnt))
+ return 0;
+
+ DRM_INFO("%s()\n", __func__);
+
+ if (panel->esd_work_pending) {
+ cancel_delayed_work_sync(&panel->esd_work);
+ panel->esd_work_pending = false;
+ }
+
+ spacemit_panel_send_cmds(panel->slave,
+ panel->info.cmds[CMD_CODE_SLEEP_IN],
+ panel->info.cmds_len[CMD_CODE_SLEEP_IN]);
+
+ atomic_set(&panel->enable_refcnt, 0);
+ return 0;
+}
+
+static int spacemit_panel_enable(struct drm_panel *p)
+{
+ struct spacemit_panel *panel = to_spacemit_panel(p);
+
+ if (atomic_read(&panel->enable_refcnt))
+ return 0;
+
+ DRM_INFO("%s()\n", __func__);
+
+ spacemit_panel_send_cmds(panel->slave,
+ panel->info.cmds[CMD_CODE_INIT],
+ panel->info.cmds_len[CMD_CODE_INIT]);
+
+ if (panel->info.esd_check_en) {
+ schedule_delayed_work(&panel->esd_work,
+ msecs_to_jiffies(1000));
+ panel->esd_work_pending = true;
+ }
+
+ atomic_set(&panel->enable_refcnt, 1);
+ return 0;
+}
+
+static int spacemit_panel_get_modes(struct drm_panel *p, struct drm_connector *connector)
+{
+ struct drm_display_mode *mode;
+ struct spacemit_panel *panel = to_spacemit_panel(p);
+
+ DRM_INFO("%s()\n", __func__);
+
+ mode = drm_mode_duplicate(connector->dev, &panel->info.mode);
+ if (!mode) {
+ DRM_ERROR("failed to add mode %ux%ux@%u\n",
+ panel->info.mode.hdisplay,
+ panel->info.mode.vdisplay,
+ 60);
+ return -ENOMEM;
+ }
+
+ drm_mode_set_name(mode);
+
+ mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ connector->display_info.width_mm = panel->info.mode.width_mm;
+ connector->display_info.height_mm = panel->info.mode.height_mm;
+
+ return 1;
+}
+
+static const struct drm_panel_funcs spacemit_panel_funcs = {
+ .get_modes = spacemit_panel_get_modes,
+ .enable = spacemit_panel_enable,
+ .disable = spacemit_panel_disable,
+ .prepare = spacemit_panel_prepare,
+ .unprepare = spacemit_panel_unprepare,
+};
+
+static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi,
+ struct mipi_dsi_msg *msg)
+{
+ const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+ if (!ops || !ops->transfer)
+ return -ENOSYS;
+
+ if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
+ msg->flags |= MIPI_DSI_MSG_USE_LPM;
+ //msg->flags |= MIPI_DSI_MSG_LASTCOMMAND;
+
+ return ops->transfer(dsi->host, msg);
+}
+
+static int spacemit_mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
+ u16 value)
+{
+ u8 tx[2] = { value & 0xff, value >> 8 };
+ int ret;
+ struct mipi_dsi_msg msg = {0x0};
+
+ msg.channel = dsi->channel;
+ msg.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE;
+ msg.tx_len = sizeof(tx);
+ msg.tx_buf = tx;
+
+ ret = mipi_dsi_device_transfer(dsi, &msg);
+
+ return (ret < 0) ? ret : 0;
+}
+
+static int spacemit_panel_esd_check(struct spacemit_panel *panel)
+{
+ struct panel_info *info = &panel->info;
+ u8 read_val = 0;
+
+ spacemit_mipi_dsi_set_maximum_return_packet_size(panel->slave, 1);
+ mipi_dsi_dcs_read(panel->slave, info->esd_check_reg,
+ &read_val, 1);
+
+ if (read_val != info->esd_check_val) {
+ DRM_ERROR("esd check failed, read value = 0x%02x\n",
+ read_val);
+ return -EINVAL;
+ } else
+ DRM_INFO("esd check, read value = 0x%02x\n", read_val);
+
+ return 0;
+}
+
+static void spacemit_panel_esd_work_func(struct work_struct *work)
+{
+ struct spacemit_panel *panel = container_of(work, struct spacemit_panel,
+ esd_work.work);
+ struct panel_info *info = &panel->info;
+ int ret;
+
+ ret = spacemit_panel_esd_check(panel);
+ if (ret) {
+ /*
+ const struct drm_encoder_helper_funcs *funcs;
+ struct drm_encoder *encoder;
+
+ encoder = panel->base.connector->encoder;
+ funcs = encoder->helper_private;
+ panel->esd_work_pending = false;
+
+ DRM_INFO("====== esd recovery start ========\n");
+ funcs->disable(encoder);
+ funcs->enable(encoder);
+ DRM_INFO("======= esd recovery end =========\n");
+ */
+ } else
+ schedule_delayed_work(&panel->esd_work,
+ msecs_to_jiffies(info->esd_check_period));
+}
+
+static int spacemit_panel_parse_dt(struct device_node *np, struct spacemit_panel *panel)
+{
+ u32 val;
+ struct device_node *lcd_node;
+ struct panel_info *info = &panel->info;
+ int bytes, rc;
+ const void *p;
+ const char *str;
+ char lcd_path[60];
+
+ rc = of_property_read_string(np, "force-attached", &str);
+ if (!rc)
+ lcd_name = str;
+
+ sprintf(lcd_path, "/lcds/%s", lcd_name);
+ lcd_node = of_find_node_by_path(lcd_path);
+ if (!lcd_node) {
+ DRM_ERROR("%pOF: could not find %s node\n", np, lcd_name);
+ return -ENODEV;
+ }
+ info->of_node = lcd_node;
+
+ rc = of_property_read_u32(lcd_node, "dsi-work-mode", &val);
+ if (!rc) {
+ if (val == DSI_MODE_CMD)
+ info->mode_flags = 0;
+ else if (val == DSI_MODE_VIDEO_BURST)
+ info->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_BURST;
+ else if (val == DSI_MODE_VIDEO_SYNC_PULSE)
+ info->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
+ else if (val == DSI_MODE_VIDEO_SYNC_EVENT)
+ info->mode_flags = MIPI_DSI_MODE_VIDEO;
+ } else {
+ DRM_ERROR("dsi work mode is not found! use video mode\n");
+ info->mode_flags = MIPI_DSI_MODE_VIDEO |
+ MIPI_DSI_MODE_VIDEO_BURST;
+ }
+
+ if (of_property_read_bool(lcd_node, "dsi-non-continuous-clock"))
+ info->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
+
+ rc = of_property_read_u32(lcd_node, "dsi-lane-number", &val);
+ if (!rc)
+ info->lanes = val;
+ else
+ info->lanes = 4;
+
+ rc = of_property_read_string(lcd_node, "dsi-color-format", &str);
+ if (rc)
+ info->format = MIPI_DSI_FMT_RGB888;
+ else if (!strcmp(str, "rgb888"))
+ info->format = MIPI_DSI_FMT_RGB888;
+ else if (!strcmp(str, "rgb666"))
+ info->format = MIPI_DSI_FMT_RGB666;
+ else if (!strcmp(str, "rgb666_packed"))
+ info->format = MIPI_DSI_FMT_RGB666_PACKED;
+ else if (!strcmp(str, "rgb565"))
+ info->format = MIPI_DSI_FMT_RGB565;
+ else
+ DRM_ERROR("dsi-color-format (%s) is not supported\n", str);
+
+ rc = of_property_read_u32(lcd_node, "width-mm", &val);
+ if (!rc)
+ info->mode.width_mm = val;
+ else
+ info->mode.width_mm = 68;
+
+ rc = of_property_read_u32(lcd_node, "height-mm", &val);
+ if (!rc)
+ info->mode.height_mm = val;
+ else
+ info->mode.height_mm = 121;
+
+ rc = of_property_read_u32(lcd_node, "esd-check-enable", &val);
+ if (!rc)
+ info->esd_check_en = val;
+
+ rc = of_property_read_u32(lcd_node, "esd-check-mode", &val);
+ if (!rc)
+ info->esd_check_mode = val;
+ else
+ info->esd_check_mode = 1;
+
+ rc = of_property_read_u32(lcd_node, "esd-check-period", &val);
+ if (!rc)
+ info->esd_check_period = val;
+ else
+ info->esd_check_period = 1000;
+
+ rc = of_property_read_u32(lcd_node, "esd-check-register", &val);
+ if (!rc)
+ info->esd_check_reg = val;
+ else
+ info->esd_check_reg = 0x0A;
+
+ rc = of_property_read_u32(lcd_node, "esd-check-value", &val);
+ if (!rc)
+ info->esd_check_val = val;
+ else
+ info->esd_check_val = 0x9C;
+
+ if (of_property_read_bool(lcd_node, "use-dcs-write"))
+ info->use_dcs = true;
+ else
+ info->use_dcs = false;
+
+ p = of_get_property(lcd_node, "read-id-command", &bytes);
+ if (p) {
+ info->cmds[CMD_CODE_READ_ID] = p;
+ info->cmds_len[CMD_CODE_READ_ID] = bytes;
+ } else
+ DRM_ERROR("can't find read-id property\n");
+
+ p = of_get_property(lcd_node, "initial-command", &bytes);
+ if (p) {
+ info->cmds[CMD_CODE_INIT] = p;
+ info->cmds_len[CMD_CODE_INIT] = bytes;
+ } else
+ DRM_ERROR("can't find initial-command property\n");
+
+ p = of_get_property(lcd_node, "sleep-in-command", &bytes);
+ if (p) {
+ info->cmds[CMD_CODE_SLEEP_IN] = p;
+ info->cmds_len[CMD_CODE_SLEEP_IN] = bytes;
+ } else
+ DRM_ERROR("can't find sleep-in-command property\n");
+
+ p = of_get_property(lcd_node, "sleep-out-command", &bytes);
+ if (p) {
+ info->cmds[CMD_CODE_SLEEP_OUT] = p;
+ info->cmds_len[CMD_CODE_SLEEP_OUT] = bytes;
+ } else
+ DRM_ERROR("can't find sleep-out-command property\n");
+
+ rc = of_get_drm_display_mode(lcd_node, &info->mode, 0,
+ OF_USE_NATIVE_MODE);
+ if (rc) {
+ DRM_ERROR("get display timing failed\n");
+ return rc;
+ }
+
+ //info->mode.vrefresh = drm_mode_vrefresh(&info->mode);
+
+ return 0;
+}
+
+static int spacemit_panel_device_create(struct device *parent,
+ struct spacemit_panel *panel)
+{
+ panel->dev.class = display_class;
+ panel->dev.parent = parent;
+ panel->dev.of_node = panel->info.of_node;
+ dev_set_name(&panel->dev, "panel%d", panel->id);
+ dev_set_drvdata(&panel->dev, panel);
+
+ return device_register(&panel->dev);
+}
+
+static int spacemit_panel_probe(struct mipi_dsi_device *slave)
+{
+ int ret;
+ struct spacemit_panel *panel;
+ struct device *dev = &slave->dev;
+ int count;
+ const char *strings[3];
+ u32 tmp;
+
+ DRM_INFO("%s()\n", __func__);
+
+ panel = devm_kzalloc(&slave->dev, sizeof(*panel), GFP_KERNEL);
+ if (!panel)
+ return -ENOMEM;
+
+ if (!of_property_read_u32(dev->of_node, "id", &tmp))
+ panel->id = tmp;
+
+ count = of_property_count_strings(dev->of_node, "vin-supply-names");
+ if (count <= 0 || count != 3) {
+ panel->vdd_2v8 = NULL;
+ panel->vdd_1v8 = NULL;
+ panel->vdd_1v2 = NULL;
+ } else {
+ of_property_read_string_array(dev->of_node, "vin-supply-names", strings, 3);
+
+ panel->vdd_2v8 = devm_regulator_get(&slave->dev, strings[0]);
+ if (IS_ERR_OR_NULL(panel->vdd_2v8)) {
+ DRM_DEBUG("get lcd regulator vdd_2v8 failed\n");
+ panel->vdd_2v8 = NULL;
+ } else {
+ regulator_set_voltage(panel->vdd_2v8, 2800000, 2800000);
+ ret = regulator_enable(panel->vdd_2v8);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_2v8 failed\n");
+ }
+
+ panel->vdd_1v8 = devm_regulator_get(&slave->dev, strings[1]);
+ if (IS_ERR_OR_NULL(panel->vdd_1v8)) {
+ DRM_DEBUG("get lcd regulator vdd_1v8 failed\n");
+ panel->vdd_1v8 = NULL;
+ } else {
+ regulator_set_voltage(panel->vdd_1v8, 1800000, 1800000);
+ ret = regulator_enable(panel->vdd_1v8);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_1v8 failed\n");
+ }
+
+ panel->vdd_1v2 = devm_regulator_get(&slave->dev, strings[2]);
+ if (IS_ERR_OR_NULL(panel->vdd_1v2)) {
+ DRM_DEBUG("get regulator vdd_1v2 failed\n");
+ panel->vdd_1v2 = NULL;
+ } else {
+ regulator_set_voltage(panel->vdd_1v2, 1200000, 1200000);
+ ret = regulator_enable(panel->vdd_1v2);
+ if (ret)
+ DRM_ERROR("enable lcd regulator vdd_1v2 failed\n");
+ }
+ }
+
+ ret = of_property_read_u32(dev->of_node, "gpios-reset", &panel->gpio_reset);
+ if (ret || !gpio_is_valid(panel->gpio_reset)) {
+ dev_err(dev, "Missing dt property: gpios-reset\n");
+ } else {
+ ret = gpio_request(panel->gpio_reset, NULL);
+ if (ret) {
+ pr_err("gpio_reset request fail\n");
+ }
+ }
+
+ ret = of_property_read_u32(dev->of_node, "gpios-bl", &panel->gpio_bl);
+ if (ret || !gpio_is_valid(panel->gpio_bl)) {
+ dev_dbg(dev, "Missing dt property: gpios-bl\n");
+ panel->gpio_bl = INVALID_GPIO;
+ } else {
+ ret = gpio_request(panel->gpio_bl, NULL);
+ if (ret) {
+ pr_err("gpio_bl request fail\n");
+ }
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, "gpios-dc", panel->gpio_dc, 2);
+ if (ret || !gpio_is_valid(panel->gpio_dc[0]) || !gpio_is_valid(panel->gpio_dc[1])) {
+ dev_err(dev, "Missing dt property: gpios-dc\n");
+ return -EINVAL;
+ } else {
+ ret = gpio_request(panel->gpio_dc[0], NULL);
+ ret |= gpio_request(panel->gpio_dc[1], NULL);
+ if (ret) {
+ pr_err("gpio_dc request fail\n");
+ return ret;
+ }
+ }
+
+ ret = of_property_read_u32_array(dev->of_node, "gpios-avdd", panel->gpio_avdd, 2);
+ if (ret || !gpio_is_valid(panel->gpio_avdd[0]) || !gpio_is_valid(panel->gpio_avdd[1])) {
+ dev_dbg(dev, "Missing avdd property: gpios-avdd\n");
+ panel->gpio_avdd[0] = INVALID_GPIO;
+ panel->gpio_avdd[1] = INVALID_GPIO;
+ } else {
+ ret = gpio_request(panel->gpio_avdd[0], NULL);
+ ret |= gpio_request(panel->gpio_avdd[1], NULL);
+ if (ret) {
+ pr_err("gpio_avdd request fail\n");
+ return ret;
+ }
+ }
+
+ if (of_property_read_u32(dev->of_node, "reset-toggle-cnt", &panel->reset_toggle_cnt))
+ panel->reset_toggle_cnt = LCD_PANEL_RESET_CNT;
+
+ if (of_property_read_u32(dev->of_node, "delay-after-reset", &panel->delay_after_reset))
+ panel->delay_after_reset = LCD_DELAY_AFTER_RESET;
+
+ ret = spacemit_panel_parse_dt(slave->dev.of_node, panel);
+ if (ret) {
+ DRM_ERROR("parse panel info failed\n");
+ return ret;
+ }
+
+ ret = spacemit_panel_device_create(&slave->dev, panel);
+ if (ret) {
+ DRM_ERROR("panel device create failed\n");
+ return ret;
+ }
+
+ panel->base.dev = &panel->dev;
+ panel->base.funcs = &spacemit_panel_funcs;
+ drm_panel_init(&panel->base, &panel->dev, &spacemit_panel_funcs, DRM_MODE_CONNECTOR_DSI);
+
+ ret = drm_panel_of_backlight(&panel->base);
+ if (ret) {
+ DRM_ERROR("panel device get backlight failed\n");
+ return ret;
+ }
+
+ drm_panel_add(&panel->base);
+ backlight_disable(panel->base.backlight);
+
+ slave->lanes = panel->info.lanes;
+ slave->format = panel->info.format;
+ slave->mode_flags = panel->info.mode_flags;
+
+ ret = mipi_dsi_attach(slave);
+ if (ret) {
+ DRM_ERROR("failed to attach dsi panel to host\n");
+ drm_panel_remove(&panel->base);
+ return ret;
+ }
+ panel->slave = slave;
+
+ spacemit_mipi_panel_sysfs_init(&panel->dev);
+ mipi_dsi_set_drvdata(slave, panel);
+
+ /*do esd init work*/
+ if (panel->info.esd_check_en) {
+ INIT_DELAYED_WORK(&panel->esd_work, spacemit_panel_esd_work_func);
+ /*
+ schedule_delayed_work(&panel->esd_work,
+ msecs_to_jiffies(2000));
+ panel->esd_work_pending = true;
+ */
+ }
+
+ atomic_set(&panel->enable_refcnt, 0);
+ atomic_set(&panel->prepare_refcnt, 0);
+
+ DRM_INFO("panel driver probe success\n");
+
+ return 0;
+}
+
+static void spacemit_panel_remove(struct mipi_dsi_device *slave)
+{
+ struct spacemit_panel *panel = mipi_dsi_get_drvdata(slave);
+ int ret;
+
+ DRM_INFO("%s()\n", __func__);
+
+ spacemit_panel_disable(&panel->base);
+ spacemit_panel_unprepare(&panel->base);
+
+ ret = mipi_dsi_detach(slave);
+ if (ret < 0)
+ DRM_ERROR("failed to detach from DSI host: %d\n", ret);
+
+ drm_panel_remove(&panel->base);
+
+ return;
+}
+
+static const struct of_device_id panel_of_match[] = {
+ { .compatible = "spacemit,mipi-panel0", },
+ { .compatible = "spacemit,mipi-panel1", },
+ { .compatible = "spacemit,mipi-panel2", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, panel_of_match);
+
+static struct mipi_dsi_driver spacemit_panel_driver = {
+ .driver = {
+ .name = "spacemit-mipi-panel-drv",
+ .of_match_table = panel_of_match,
+ },
+ .probe = spacemit_panel_probe,
+ .shutdown = spacemit_panel_remove,
+};
+module_mipi_dsi_driver(spacemit_panel_driver);
+
+MODULE_DESCRIPTION("Spacemit MIPI Panel Driver");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_MIPI_PANEL_H_
+#define _SPACEMIT_MIPI_PANEL_H_
+
+#include <drm/drm_print.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_panel.h>
+#include <linux/backlight.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <soc/spacemit/spacemit_panel.h>
+
+#define INVALID_GPIO 0xFFFFFFFF
+
+#define LCD_PANEL_RESET_CNT 2
+#define LCD_DELAY_AFTER_RESET 100
+
+enum {
+ CMD_CODE_INIT = 0,
+ CMD_CODE_SLEEP_IN,
+ CMD_CODE_SLEEP_OUT,
+ CMD_CODE_READ_ID,
+ CMD_CODE_READ_POWER,
+ CMD_CODE_MAX,
+};
+
+enum {
+ DSI_MODE_CMD = 0,
+ DSI_MODE_VIDEO_BURST,
+ DSI_MODE_VIDEO_SYNC_PULSE,
+ DSI_MODE_VIDEO_SYNC_EVENT,
+};
+
+struct panel_info {
+ /* common parameters */
+ struct device_node *of_node;
+ struct drm_display_mode mode;
+ const void *cmds[CMD_CODE_MAX];
+ int cmds_len[CMD_CODE_MAX];
+
+ /* esd check parameters*/
+ bool esd_check_en;
+ u8 esd_check_mode;
+ u16 esd_check_period;
+ u32 esd_check_reg;
+ u32 esd_check_val;
+
+ /* MIPI DSI specific parameters */
+ u32 format;
+ u32 lanes;
+ u32 mode_flags;
+ bool use_dcs;
+};
+
+struct spacemit_panel {
+ int id;
+ struct device dev;
+ struct drm_panel base;
+ struct mipi_dsi_device *slave;
+ struct panel_info info;
+
+ struct delayed_work esd_work;
+ bool esd_work_pending;
+
+ struct regulator *vdd_1v2;
+ struct regulator *vdd_1v8;
+ struct regulator *vdd_2v8;
+ u32 gpio_reset;
+ u32 gpio_bl;
+ u32 gpio_dc[2];
+ u32 gpio_avdd[2];
+ atomic_t enable_refcnt;
+ atomic_t prepare_refcnt;
+ u32 reset_toggle_cnt;
+ u32 delay_after_reset;
+};
+
+struct spacemit_drm_notifier_mipi
+{
+ void *blank;
+};
+
+static BLOCKING_NOTIFIER_HEAD(drm_notifier_list);
+
+int spacemit_drm_notifier_call_chain(unsigned long val, void *v);
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_blend.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include <drm/drm_color_mgmt.h>
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include "spacemit_cmdlist.h"
+#include "spacemit_dmmu.h"
+#include "spacemit_dpu.h"
+#include "spacemit_drm.h"
+#include "spacemit_gem.h"
+#include "spacemit_lib.h"
+#include "dpu/dpu_saturn.h"
+#include "dpu/dpu_trace.h"
+
+//as per weston requirement, suppoted modifiers need to be reported to user space,
+//which is different from sf
+static const uint64_t supported_format_modifiers[] = {
+ DRM_FORMAT_MOD_LINEAR,
+ DRM_FORMAT_MOD_INVALID
+};
+
+struct spacemit_plane *to_spacemit_plane(struct drm_plane *plane)
+{
+ return container_of(plane, struct spacemit_plane, plane);
+}
+
+static int spacemit_plane_check_rdma(const struct spacemit_hw_rdma *rdma, u32 rdma_id, struct drm_plane_state *state)
+{
+ unsigned int rot = state->rotation;
+ unsigned int zpos = state->zpos;
+ u32 format = state->fb->format->format;
+ u16 hw_formats = rdma[rdma_id].formats;
+ u16 hw_rots = rdma[rdma_id].rots;
+ bool afbc = (state->fb->modifier > 0);
+ const struct drm_format_info *info = drm_format_info(format);
+ struct spacemit_dpu *dpu = crtc_to_dpu(state->crtc);
+
+ trace_spacemit_plane_check_rdma(dpu->dev_id);
+ if ((info->is_yuv) && !afbc && ((hw_formats & FORMAT_RAW_YUV) == 0)) {
+ DRM_DEBUG("rdma%d doesn't support RAW YUV format with zpos%d!\n", rdma_id, zpos);
+ return -EINVAL;
+ }
+
+ if (afbc && ((hw_formats & FORMAT_AFBC) == 0)) {
+ DRM_DEBUG("rdma%d doesn't support AFBC format with zpos%d!\n", rdma_id, zpos);
+ return -EINVAL;
+ }
+
+ if (rot == DRM_MODE_ROTATE_90 || rot == DRM_MODE_ROTATE_270) {
+ if (afbc) {
+ if ((hw_rots & ROTATE_AFBC_90_270) == 0) {
+ DRM_DEBUG("rdma%d doesn't support AFBC 90/270 rotation with zpos%d\n", rdma_id, zpos);
+ return -EINVAL;
+ }
+ } else {
+ if ((hw_rots & ROTATE_RAW_90_270) == 0) {
+ DRM_DEBUG("rdma%d doesn't support RAW 90/270 rotation with zpos%d!\n", rdma_id, zpos);
+ return -EINVAL;
+ }
+ }
+ } else {
+ if ((hw_rots & ROTATE_COMMON) == 0) {
+ DRM_DEBUG("rdma%d doesn't support common rotation with zpos%d!\n", rdma_id, zpos);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int spacemit_plane_atomic_check_hdr_coefs (struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct spacemit_plane_state *apstate = to_spacemit_plane_state(state);
+ struct drm_property_blob *blob;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ int size = hwdev->hdr_coef_size;
+ int *coef_data;
+ int n = 0;
+
+ if ((apstate->hdr_coefs_blob_prop)){
+ blob = apstate->hdr_coefs_blob_prop;
+ coef_data = (int *)blob->data;
+
+ for (n = 0; n < size; n++){
+ if ((coef_data[n] > 65535) || (coef_data[n] < 0)){
+ DRM_ERROR("HDR coef is invalid %d\n", coef_data[n]);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int spacemit_plane_atomic_check_scale_coefs (struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct spacemit_plane_state *apstate = to_spacemit_plane_state(state);
+ struct drm_property_blob *blob;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ int size = hwdev->scale_coef_size;
+ int *coef_data;
+ int n = 0;
+
+ if ((apstate->scale_coefs_blob_prop)){
+ blob = apstate->scale_coefs_blob_prop;
+ coef_data = (int *)blob->data;
+
+ for (n = 0; n < size; n++){
+ if ((coef_data[n] > 32766) || (coef_data[n] < -32767)){
+ DRM_ERROR("scale coef is invalid %d\n", coef_data[n]);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int spacemit_plane_atomic_check(struct drm_plane *plane,
+ struct drm_atomic_state *atomic_state)
+{
+ struct drm_plane_state *state = drm_atomic_get_new_plane_state(atomic_state, plane);
+ struct drm_framebuffer *fb = state->fb;
+ u16 pixel_alpha = state->pixel_blend_mode;
+ u32 src_w, src_h, src_x, src_y;
+ u32 crtc_w, crtc_h;
+ struct spacemit_plane_state *cur_state = to_spacemit_plane_state(state);
+ u32 cur_rdma_id = cur_state->rdma_id;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ const struct spacemit_hw_rdma *rdmas = hwdev->rdmas;
+ struct spacemit_dpu *dpu = NULL;
+
+ if (!state->crtc || WARN_ON(!state->fb)) {
+ return 0;
+ }
+
+ dpu = crtc_to_dpu(state->crtc);
+ trace_spacemit_plane_atomic_check(dpu->dev_id);
+
+ src_x = state->src_x >> 16;
+ src_y = state->src_y >> 16;
+ src_w = state->src_w >> 16;
+ src_h = state->src_h >> 16;
+ crtc_w = state->crtc_w;
+ crtc_h = state->crtc_h;
+
+ /* For multi planes, only support planes with its offsets is set */
+ if (fb->format->num_planes > 3 ||
+ (fb->format->num_planes > 2 && fb->offsets[2] == 0) ||
+ (fb->format->num_planes > 1 && fb->offsets[1] == 0)) {
+ DRM_ERROR("%s, Unsupported plane format: plane_num:%d offsets[1]:%d offsets[2]:%d\n", \
+ __func__, fb->format->num_planes, fb->offsets[1], fb->offsets[2]);
+ return -EINVAL;
+ }
+
+ if (fb->format->num_planes > 1 && fb->modifier) {
+ DRM_ERROR("%s, Unsupported afbc with plane_num:%d\n", __func__, fb->format->num_planes);
+ return -EINVAL;
+ }
+
+ if (fb->format->format == DRM_FORMAT_NV12 || fb->format->format == DRM_FORMAT_YUV420_8BIT) {
+ if (src_x % 2 || src_y % 2 || src_w % 2 || src_h % 2) {
+ DRM_ERROR("YUV420 coordinations must be even! src_x:%d src_y:%d \
+ src_w:%d src_h:%d\n", src_x, src_y, src_w, src_h);
+ return -EINVAL;
+ }
+ }
+
+ /* adjust rdma id */
+ if (src_w == 0 && src_h == 0)
+ cur_rdma_id = RDMA_INVALID_ID;
+ else {
+ /* In case the userspace hasn't set rdma id */
+ if (cur_rdma_id == RDMA_INVALID_ID)
+ cur_rdma_id = state->zpos;
+ }
+ cur_state->rdma_id = cur_rdma_id;
+
+ /* Skip solid color */
+ if (cur_rdma_id != RDMA_INVALID_ID) {
+ if (src_w != crtc_w || src_h != crtc_h)
+ cur_state->use_scl = true;
+ else
+ cur_state->use_scl = false;
+ if (cur_rdma_id < hwdev->rdma_nums) {
+ if (spacemit_plane_check_rdma(rdmas, cur_rdma_id, state))
+ return -EINVAL;
+ } else {
+ DRM_ERROR("Invalid rdma id:%d\n", cur_rdma_id);
+ return -EINVAL;
+ }
+
+ if (dpu->core->cal_layer_fbcmem_size(plane, state)) {
+ DRM_ERROR("plane:%d Invalid fbcmem size\n", state->zpos);
+ return -EINVAL;
+ }
+
+ if(dpu->core->calc_plane_mclk_bw(plane, state)) {
+ DRM_INFO("plane:%d unsupported mclk or bandwidth\n", state->zpos);
+ return -EINVAL;
+ }
+ }
+
+ if (spacemit_plane_atomic_check_hdr_coefs(plane, state)){
+ DRM_ERROR("The value of hdr coef is invalid\n");
+ return -EINVAL;
+ }
+
+ if (spacemit_plane_atomic_check_scale_coefs(plane, state)){
+ DRM_ERROR("The value of scale coef is invalid\n");
+ return -EINVAL;
+ }
+
+ /* HW can't support plane + pixel blending */
+ if ((state->alpha != DRM_BLEND_ALPHA_OPAQUE) &&
+ (pixel_alpha != DRM_MODE_BLEND_PIXEL_NONE) &&
+ fb->format->has_alpha) {
+ DRM_ERROR("Can't support mixed blend mode!\n");
+ return -EINVAL;
+ }
+
+ cur_state->format = spacemit_plane_hw_get_format_id(fb->format->format);
+ if (cur_state->format == SPACEMIT_DPU_INVALID_FORMAT_ID) {
+ DRM_ERROR("Can't support format:0x%x\n", fb->format->format);
+ return -EINVAL;
+ }
+
+ /* Use default values as they are not actually used now */
+ cur_state->right_image = 0;
+ cur_state->is_offline = 1;
+ return 0;
+}
+
+static void spacemit_plane_atomic_update(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ int ret = 0;
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+ struct spacemit_dpu *dpu = crtc_to_dpu(plane->state->crtc);
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(plane->state);
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u32 rdma_id = spacemit_pstate->rdma_id;
+
+ DRM_DEBUG("%s()\n", __func__);
+ trace_spacemit_plane_atomic_update(dpu->dev_id);
+
+ spacemit_plane_update_hw_channel(plane);
+
+ spacemit_update_hdr_matrix(plane, spacemit_pstate);
+ spacemit_update_csc_matrix(plane, old_state);
+
+ /* No need for solid color layer */
+ if (rdma_id < hwdev->rdma_nums) {
+ u8 tbu_id;
+
+ spacemit_pstate->mmu_tbl.size = ((PAGE_ALIGN(plane->state->fb->obj[0]->size) >> PAGE_SHIFT) +
+ HW_ALIGN_TTB_NUM) * 4;
+ spacemit_pstate->mmu_tbl.va = dma_alloc_coherent(dpu->dev, spacemit_pstate->mmu_tbl.size, \
+ &spacemit_pstate->mmu_tbl.pa, GFP_KERNEL | __GFP_ZERO);
+ if (spacemit_pstate->mmu_tbl.va == NULL) {
+ DRM_ERROR("Failed to allocate %d bytes for dpu plane%d mmu table\n",
+ spacemit_pstate->mmu_tbl.size, plane->state->zpos);
+ return;
+ }
+ tbu_id = !spacemit_pstate->right_image ? (rdma_id * 2) : (rdma_id * 2 + 1);
+ ret = spacemit_dmmu_map(plane->state->fb, &spacemit_pstate->mmu_tbl, tbu_id, false);
+ if (!ret)
+ cmdlist_regs_packing(plane);
+ else
+ DRM_ERROR("%s failed to map plane with ret = %d\n", __func__, ret);
+ }
+}
+
+static void spacemit_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_atomic_state *state)
+{
+ struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
+ DRM_DEBUG("%s()\n", __func__);
+
+ spacemit_dmmu_unmap(plane);
+ spacemit_plane_disable_hw_channel(plane, old_state);
+}
+
+// static void spacemit_plane_atomic_cleanup_fb(struct drm_plane *plane,
+// struct drm_plane_state *old_state)
+// {
+
+// }
+
+static void spacemit_plane_reset(struct drm_plane *plane)
+{
+ struct spacemit_plane *p = to_spacemit_plane(plane);
+ struct spacemit_plane_state *s;
+ struct spacemit_drm_private *priv = plane->dev->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ struct spacemit_dpu *dpu = NULL;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (plane->state) {
+ s = to_spacemit_plane_state(plane->state);
+ dpu = crtc_to_dpu(plane->crtc);
+ trace_spacemit_plane_reset(dpu->dev_id);
+ __drm_atomic_helper_plane_destroy_state(plane->state);
+ kfree(s);
+ plane->state = NULL;
+ }
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (s) {
+ __drm_atomic_helper_plane_reset(plane, &s->state);
+ s->state.zpos = hwdev->plane_nums - p->hw_pid - 1;
+ s->rdma_id = RDMA_INVALID_ID;
+ s->is_offline = 1;
+ s->scaler_id = SCALER_INVALID_ID;
+ }
+}
+
+static struct drm_plane_state *
+spacemit_plane_atomic_duplicate_state(struct drm_plane *plane)
+{
+ struct spacemit_plane_state *s;
+ struct spacemit_plane_state *old_state = to_spacemit_plane_state(plane->state);
+ struct spacemit_dpu *dpu = NULL;
+
+ if (plane->crtc) {
+ dpu = crtc_to_dpu(plane->crtc);
+ trace_spacemit_plane_atomic_duplicate_state(dpu->dev_id);
+ }
+ DRM_DEBUG("%s()\n", __func__);
+
+ s = kzalloc(sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return NULL;
+
+ __drm_atomic_helper_plane_duplicate_state(plane, &s->state);
+
+ WARN_ON(s->state.plane != plane);
+
+ s->is_offline = old_state->is_offline;
+ s->rdma_id = old_state->rdma_id;
+ s->format = old_state->format;
+ s->right_image = old_state->right_image;
+ s->scaler_id = SCALER_INVALID_ID;
+ s->use_scl = false;
+ s->fbcmem_size = 0;
+ if (s->hdr_coefs_blob_prop)
+ drm_property_blob_get(s->hdr_coefs_blob_prop);
+ if (s->scale_coefs_blob_prop)
+ drm_property_blob_get(s->scale_coefs_blob_prop);
+ return &s->state;
+}
+
+static void spacemit_plane_atomic_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct spacemit_plane_state *spacemit_pstate = to_spacemit_plane_state(state);
+ struct spacemit_dpu *dpu = NULL;
+ DRM_DEBUG("%s()\n", __func__);
+
+ if (state->crtc) {
+ dpu = crtc_to_dpu(state->crtc);
+
+ if (spacemit_pstate->mmu_tbl.va)
+ dma_free_coherent(dpu->dev, spacemit_pstate->mmu_tbl.size, \
+ spacemit_pstate->mmu_tbl.va, spacemit_pstate->mmu_tbl.pa);
+
+ if (spacemit_pstate->cl.va)
+ dma_free_coherent(dpu->dev, spacemit_pstate->cl.size, \
+ spacemit_pstate->cl.va, spacemit_pstate->cl.pa);
+ trace_spacemit_plane_atomic_destroy_state(dpu->dev_id);
+ }
+ __drm_atomic_helper_plane_destroy_state(state);
+
+ if (spacemit_pstate->hdr_coefs_blob_prop)
+ drm_property_blob_put(spacemit_pstate->hdr_coefs_blob_prop);
+
+ if (spacemit_pstate->scale_coefs_blob_prop)
+ drm_property_blob_put(spacemit_pstate->scale_coefs_blob_prop);
+
+ kfree(to_spacemit_plane_state(state));
+}
+
+static int spacemit_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ u64 val)
+{
+ struct spacemit_plane *p = to_spacemit_plane(plane);
+ struct spacemit_plane_state *s = to_spacemit_plane_state(state);
+ bool replaced = false;
+ int ret = 0;
+
+ DRM_DEBUG("%s() name = %s, val = %llu\n",
+ __func__, property->name, val);
+
+ if (property == p->rdma_id_property)
+ s->rdma_id = val;
+ else if (property == p->solid_color_property)
+ s->solid_color = val;
+ else if (property == p->hdr_coef_property) {
+ ret = spacemit_atomic_replace_property_blob_from_id(plane->dev,
+ &s->hdr_coefs_blob_prop,
+ val,
+ -1,
+ sizeof(int),
+ &replaced);
+ return ret;
+ } else if (property == p->scale_coef_property) {
+ ret = spacemit_atomic_replace_property_blob_from_id(plane->dev,
+ &s->scale_coefs_blob_prop,
+ val,
+ -1,
+ sizeof(int),
+ &replaced);
+ return ret;
+ } else {
+ DRM_ERROR("property %s is invalid\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int spacemit_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ u64 *val)
+{
+ struct spacemit_plane *p = to_spacemit_plane(plane);
+ const struct spacemit_plane_state *s = to_spacemit_plane_state(state);
+
+ DRM_DEBUG("%s() name = %s\n", __func__, property->name);
+
+ if (property == p->rdma_id_property)
+ *val = s->rdma_id;
+ else if (property == p->solid_color_property)
+ *val = s->solid_color;
+ else if (property == p->hdr_coef_property){
+ if (s->hdr_coefs_blob_prop)
+ *val = (s->hdr_coefs_blob_prop) ? s->hdr_coefs_blob_prop->base.id : 0;
+ }
+ else if (property == p->scale_coef_property){
+ if (s->scale_coefs_blob_prop)
+ *val = (s->scale_coefs_blob_prop) ? s->scale_coefs_blob_prop->base.id : 0;
+ }
+ else {
+ DRM_ERROR("property %s is invalid\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const char * const color_encoding_name[] = {
+ [DRM_COLOR_YCBCR_BT601] = "ITU-R BT.601 YCbCr",
+ [DRM_COLOR_YCBCR_BT709] = "ITU-R BT.709 YCbCr",
+ [DRM_COLOR_YCBCR_BT2020] = "ITU-R BT.2020 YCbCr",
+};
+
+static const char * const color_range_name[] = {
+ [DRM_COLOR_YCBCR_FULL_RANGE] = "YCbCr full range",
+ [DRM_COLOR_YCBCR_LIMITED_RANGE] = "YCbCr limited range",
+};
+
+int spacemit_drm_plane_create_color_properties(struct drm_plane *plane,
+ u32 supported_encodings,
+ u32 supported_ranges,
+ enum drm_color_encoding default_encoding,
+ enum drm_color_range default_range)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_property *prop;
+ struct drm_prop_enum_list enum_list[max_t(int, DRM_COLOR_ENCODING_MAX,
+ DRM_COLOR_RANGE_MAX)];
+ int i, len;
+
+ if (WARN_ON(supported_encodings == 0 ||
+ (supported_encodings & -BIT(DRM_COLOR_ENCODING_MAX)) != 0 ||
+ (supported_encodings & BIT(default_encoding)) == 0))
+ return -EINVAL;
+
+ if (WARN_ON(supported_ranges == 0 ||
+ (supported_ranges & -BIT(DRM_COLOR_RANGE_MAX)) != 0 ||
+ (supported_ranges & BIT(default_range)) == 0))
+ return -EINVAL;
+
+ len = 0;
+ for (i = 0; i < DRM_COLOR_ENCODING_MAX; i++) {
+ if ((supported_encodings & BIT(i)) == 0)
+ continue;
+
+ enum_list[len].type = i;
+ enum_list[len].name = color_encoding_name[i];
+ len++;
+ }
+
+ prop = drm_property_create_enum(dev, 0, "COLOR_ENCODING",
+ enum_list, len);
+ if (!prop)
+ return -ENOMEM;
+ plane->color_encoding_property = prop;
+ drm_object_attach_property(&plane->base, prop, default_encoding);
+ if (plane->state)
+ plane->state->color_encoding = default_encoding;
+
+ len = 0;
+ for (i = 0; i < DRM_COLOR_RANGE_MAX; i++) {
+ if ((supported_ranges & BIT(i)) == 0)
+ continue;
+
+ enum_list[len].type = i;
+ enum_list[len].name = color_range_name[i];
+ len++;
+ }
+
+ prop = drm_property_create_enum(dev, 0, "COLOR_RANGE",
+ enum_list, len);
+ if (!prop)
+ return -ENOMEM;
+ plane->color_range_property = prop;
+ drm_object_attach_property(&plane->base, prop, default_range);
+ if (plane->state)
+ plane->state->color_range = default_range;
+
+ return 0;
+}
+
+static int spacemit_plane_create_properties(struct spacemit_plane *p, int index)
+{
+ struct drm_property *prop;
+ unsigned int support_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE);
+ int ret = 0;
+
+ DRM_DEBUG("%s()\n", __func__);
+ /* create rotation property */
+ drm_plane_create_rotation_property(&p->plane,
+ DRM_MODE_ROTATE_0,
+ DRM_MODE_ROTATE_MASK |
+ DRM_MODE_REFLECT_MASK);
+
+ /* create zpos property */
+ drm_plane_create_zpos_immutable_property(&p->plane, index);
+
+ /* create layer alpha property */
+ drm_plane_create_alpha_property(&p->plane);
+
+ /* create blend mode property */
+ drm_plane_create_blend_mode_property(&p->plane, support_modes);
+
+ prop = drm_property_create_range(p->plane.dev, 0,
+ "RDMA_ID", 0, ULLONG_MAX);
+ if (!prop)
+ return -ENOMEM;
+ drm_object_attach_property(&p->plane.base, prop, 0);
+ p->rdma_id_property = prop;
+
+ prop = drm_property_create_range(p->plane.dev, 0,
+ "SOLID_COLOR", 0, ULLONG_MAX);
+ if (!prop)
+ return -ENOMEM;
+ drm_object_attach_property(&p->plane.base, prop, 0);
+ p->solid_color_property = prop;
+
+ prop = drm_property_create(p->plane.dev,
+ DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
+ "hdr_coefs", 0);
+ if (!prop)
+ return -ENOMEM;
+ drm_object_attach_property(&p->plane.base, prop, 0);
+ p->hdr_coef_property = prop;
+
+ prop = drm_property_create(p->plane.dev,
+ DRM_MODE_PROP_ATOMIC | DRM_MODE_PROP_BLOB,
+ "scale_coefs", 0);
+ if (!prop)
+ return -ENOMEM;
+ drm_object_attach_property(&p->plane.base, prop, 0);
+ p->scale_coef_property = prop;
+
+ ret = spacemit_drm_plane_create_color_properties(&p->plane,
+ BIT(DRM_COLOR_YCBCR_BT601) | \
+ BIT(DRM_COLOR_YCBCR_BT709) | \
+ BIT(DRM_COLOR_YCBCR_BT2020),
+ BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | \
+ BIT(DRM_COLOR_YCBCR_FULL_RANGE),
+ DRM_COLOR_YCBCR_BT601, DRM_COLOR_YCBCR_LIMITED_RANGE);
+ if(ret)
+ DRM_ERROR("Failed to create color properties %d\n", ret);
+
+ return 0;
+}
+
+static const struct drm_plane_helper_funcs spacemit_plane_helper_funcs = {
+ .atomic_check = spacemit_plane_atomic_check,
+ .atomic_update = spacemit_plane_atomic_update,
+ .atomic_disable = spacemit_plane_atomic_disable,
+};
+
+static const struct drm_plane_funcs spacemit_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = drm_plane_cleanup,
+ .reset = spacemit_plane_reset,
+ .atomic_duplicate_state = spacemit_plane_atomic_duplicate_state,
+ .atomic_destroy_state = spacemit_plane_atomic_destroy_state,
+ .atomic_set_property = spacemit_plane_atomic_set_property,
+ .atomic_get_property = spacemit_plane_atomic_get_property,
+};
+
+struct drm_plane *spacemit_plane_init(struct drm_device *drm,
+ struct spacemit_dpu *dpu)
+{
+ struct drm_plane *primary = NULL;
+ struct spacemit_plane *p = NULL;
+ enum drm_plane_type plane_type;
+ int err, i, j;
+ u32 *formats;
+ struct spacemit_drm_private *priv = drm->dev_private;
+ struct spacemit_hw_device *hwdev = priv->hwdev;
+ u8 n_planes = hwdev->plane_nums;
+ u8 n_formats = hwdev->n_formats;
+ u8 n_fbcmems = hwdev->n_fbcmems;
+ u8 n_rdmas = hwdev->rdma_nums;
+ u32 plane_crtc_mask;
+
+ trace_spacemit_plane_init(dpu->dev_id);
+ if (n_fbcmems * 2 != n_rdmas) {
+ DRM_ERROR("Unmatched rdma and fbcmem numbers, \
+ n_rdmas:%d n_fbcmems:%d!\n", n_rdmas, n_fbcmems);
+ err = -EINVAL;
+ return ERR_PTR(err);
+ }
+
+ formats = kcalloc(n_formats, sizeof(*formats), GFP_KERNEL);
+ if (!formats) {
+ err = -ENOMEM;
+ return ERR_PTR(err);
+ }
+
+ /* Create all planes first. They can all be put to any CRTC. */
+ plane_crtc_mask = (1 << priv->num_pipes) - 1;
+
+ for (i = 0; i < n_planes; i++) {
+ p = devm_kzalloc(drm->dev, sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ kfree(formats);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* build the list of DRM supported formats based on the map */
+ for (j = 0; j < n_formats; j++)
+ formats[j] = hwdev->formats[j].format;
+
+ plane_type = (i < priv->num_pipes)
+ ? DRM_PLANE_TYPE_PRIMARY
+ : DRM_PLANE_TYPE_OVERLAY;
+
+ err = drm_universal_plane_init(drm, &p->plane, plane_crtc_mask,
+ &spacemit_plane_funcs, formats,
+ n_formats, supported_format_modifiers,
+ plane_type, NULL);
+ if (err) {
+ DRM_ERROR("fail to init %s plane%d\n", (i < priv->num_pipes) ? "primary" : "overlay", i);
+ return ERR_PTR(err);
+ }
+
+ drm_plane_helper_add(&p->plane, &spacemit_plane_helper_funcs);
+
+ spacemit_plane_create_properties(p, i);
+
+ p->hwdev = hwdev;
+ p->hw_pid = n_planes - i - 1;
+ if (i == 0)
+ primary = &p->plane;
+ }
+
+ kfree(formats);
+
+ if (p)
+ DRM_INFO("dpu plane init ok\n");
+
+ return primary;
+}
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_fourcc.h>
+//#include <drm/drm_gem_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_of.h>
+#include <linux/component.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_graph.h>
+#include "spacemit_lib.h"
+#include "spacemit_dpu.h"
+#include "spacemit_wb.h"
+#include "sysfs/sysfs_display.h"
+
+static const u32 spacemit_wb_formats[] = {
+ DRM_FORMAT_XRGB8888,
+};
+
+void spacemit_wb_atomic_commit(struct drm_device *drm, struct drm_atomic_state *old_state)
+{
+ struct drm_crtc *crtc;
+ struct spacemit_dpu *dpu;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_writeback_connector *wb_conn;
+ struct drm_connector_state *conn_state;
+ int i;
+
+ for_each_new_crtc_in_state(old_state, crtc, new_crtc_state, i) {
+ if (!new_crtc_state->active)
+ continue;
+
+ dpu = crtc_to_dpu(crtc);
+ wb_conn = &dpu->wb_connector;
+ conn_state = wb_conn->base.state;
+
+ if (!conn_state)
+ return;
+
+ if (conn_state->writeback_job)
+ drm_writeback_queue_job(wb_conn, conn_state);
+ }
+}
+
+static int spacemit_wb_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ DRM_DEBUG("%s()\n", __func__);
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs spacemit_wb_encoder_helper_funcs = {
+ .atomic_check = spacemit_wb_encoder_atomic_check,
+};
+
+static const struct drm_encoder_funcs spacemit_wb_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static int spacemit_wb_connector_get_modes(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ return drm_add_modes_noedid(connector, dev->mode_config.max_width,
+ dev->mode_config.max_height);
+}
+
+static enum drm_mode_status
+spacemit_wb_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ enum drm_mode_status mode_status = MODE_OK;
+
+ DRM_DEBUG("%s(%s)\n", __func__, mode->name);
+
+ return mode_status;
+}
+
+static enum drm_connector_status
+spacemit_wb_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void spacemit_wb_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_helper_funcs spacemit_wb_connector_helper_funcs = {
+ .get_modes = spacemit_wb_connector_get_modes,
+ .mode_valid = spacemit_wb_connector_mode_valid,
+};
+
+void spacemit_wb_drm_atomic_helper_connector_destroy_state(struct drm_connector *connector,
+ struct drm_connector_state *state)
+{
+ struct drm_crtc *crtc = NULL;
+ struct spacemit_dpu *dpu = NULL;
+
+ crtc = state->crtc;
+ dpu = crtc_to_dpu(crtc);
+
+ if (dpu->mmu_tbl.va)
+ dma_free_coherent(dpu->dev, dpu->mmu_tbl.size, \
+ dpu->mmu_tbl.va, dpu->mmu_tbl.pa);
+}
+
+static const struct drm_connector_funcs spacemit_wb_connector_funcs = {
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = spacemit_wb_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = spacemit_wb_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = spacemit_wb_drm_atomic_helper_connector_destroy_state,
+};
+
+static int spacemit_wb_connector_init(struct drm_device *drm, struct drm_crtc *crtc)
+{
+ int ret;
+ struct spacemit_dpu *dpu = crtc_to_dpu(crtc);
+
+ dpu->wb_connector.encoder.possible_crtcs = 1 << drm_crtc_index(crtc);
+
+ drm_connector_helper_add(&dpu->wb_connector.base,
+ &spacemit_wb_connector_helper_funcs);
+
+ ret = drm_writeback_connector_init(drm, &dpu->wb_connector,
+ &spacemit_wb_connector_funcs,
+ &spacemit_wb_encoder_helper_funcs,
+ spacemit_wb_formats,
+ ARRAY_SIZE(spacemit_wb_formats),
+ 1 << drm_crtc_index(crtc));
+ if (ret) {
+ DRM_ERROR("drm_connector_init() failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+int spacemit_wb_init(struct drm_device *drm, struct drm_crtc *dpu_crtc)
+{
+ struct drm_crtc *crtc = dpu_crtc;
+ int ret;
+
+ ret = spacemit_wb_connector_init(drm, crtc);
+ if (ret)
+ return -1;
+
+ return ret;
+}
+
+static int spacemit_wb_device_create(struct spacemit_wb *wb, struct device *parent)
+{
+ int ret;
+
+ wb->dev.class = display_class;
+ wb->dev.parent = parent;
+ wb->dev.of_node = parent->of_node;
+ dev_set_name(&wb->dev, "wb%d", wb->ctx.id);
+ dev_set_drvdata(&wb->dev, wb);
+
+ ret = device_register(&wb->dev);
+ if (ret)
+ DRM_ERROR("wb device register failed\n");
+
+ return ret;
+}
+
+static int spacemit_wb_context_init(struct spacemit_wb *wb, struct device_node *np)
+{
+ struct spacemit_wb_device *ctx = &wb->ctx;
+ u32 tmp;
+
+ if (!of_property_read_u32(np, "dev-id", &tmp))
+ ctx->id = tmp;
+
+ return 0;
+}
+
+static int spacemit_wb_bind(struct device *dev, struct device *master, void *data)
+{
+
+ return 0;
+}
+
+static void spacemit_wb_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ /* do nothing */
+ DRM_DEBUG("%s()\n", __func__);
+}
+
+static const struct component_ops spacemit_wb_component_ops = {
+ .bind = spacemit_wb_bind,
+ .unbind = spacemit_wb_unbind,
+};
+
+static int spacemit_wb_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spacemit_wb *wb;
+ int ret;
+
+ DRM_DEBUG("%s()\n", __func__);
+
+ wb = devm_kzalloc(&pdev->dev, sizeof(*wb), GFP_KERNEL);
+ if (!wb) {
+ DRM_ERROR("failed to allocate wb data.\n");
+ return -ENOMEM;
+ }
+
+ ret = spacemit_wb_context_init(wb, np);
+ if (ret) {
+ return -EINVAL;
+ }
+
+ spacemit_wb_device_create(wb, &pdev->dev);
+ //spacemit_wb_sysfs_init(&wb->dev);
+ platform_set_drvdata(pdev, wb);
+
+ return component_add(&pdev->dev, &spacemit_wb_component_ops);
+}
+
+static int spacemit_wb_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &spacemit_wb_component_ops);
+ return 0;
+}
+
+static const struct of_device_id spacemit_wb_of_match[] = {
+ {.compatible = "spacemit,wb0"},
+ {.compatible = "spacemit,wb1"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, spacemit_wb_of_match);
+
+struct platform_driver spacemit_wb_driver = {
+ .probe = spacemit_wb_probe,
+ .remove = spacemit_wb_remove,
+ .driver = {
+ .name = "spacemit-wb-drv",
+ .of_match_table = spacemit_wb_of_match,
+ },
+};
+
+// module_platform_driver(spacemit_wb_driver);
+static int spacemit_wb_driver_init(void)
+{
+ return platform_driver_register(&spacemit_wb_driver);
+}
+late_initcall(spacemit_wb_driver_init);
+
+MODULE_DESCRIPTION("Spacemit WB Driver");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SPACEMIT_MW_H_
+#define _SPACEMIT_MW_H_
+
+#include <linux/of.h>
+#include <linux/device.h>
+#include <video/videomode.h>
+
+#include <drm/drm_print.h>
+#include <drm/drm_writeback.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_bridge.h>
+
+#include "spacemit_lib.h"
+
+enum spacemit_wb_loc {
+ SPACEMIT_WB_COMP0 = 0,
+ SPACEMIT_WB_COMP1,
+ SPACEMIT_WB_COMP2,
+ SPACEMIT_WB_COMP3,
+ SPACEMIT_WB_COMP4,
+ SPACEMIT_WB_RCH0 = 8,
+ SPACEMIT_WB_RCH1,
+ SPACEMIT_WB_RCH2,
+ SPACEMIT_WB_RCH3,
+ SPACEMIT_WB_RCH4,
+ SPACEMIT_WB_RCH5,
+ SPACEMIT_WB_RCH6,
+ SPACEMIT_WB_RCH7,
+ SPACEMIT_WB_RCH8,
+ SPACEMIT_WB_RCH9,
+ SPACEMIT_WB_RCH10,
+ SPACEMIT_WB_RCH11,
+ SPACEMIT_WB_POST0 = 24,
+ SPACEMIT_WB_POST1,
+ SPACEMIT_WB_POST2,
+};
+
+struct spacemit_wb_device {
+ uint32_t id;
+ struct videomode vm;
+ int status;
+};
+
+struct spacemit_wb {
+ struct device dev;
+ struct drm_encoder encoder;
+ struct spacemit_wb_device ctx;
+};
+
+void saturn_wb_config(struct spacemit_dpu *dpu);
+
+#endif
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "sysfs_display.h"
+
+struct class *display_class;
+EXPORT_SYMBOL_GPL(display_class);
+
+#ifndef MODULE
+static int __init display_class_init(void)
+#else
+int display_class_init(void)
+#endif
+{
+ pr_info("display class register\n");
+
+ display_class = class_create("display");
+ if (IS_ERR(display_class)) {
+ pr_err("Unable to create display class\n");
+ return PTR_ERR(display_class);
+ }
+
+ return 0;
+}
+
+#ifndef MODULE
+postcore_initcall(display_class_init);
+#endif
+
+MODULE_DESCRIPTION("Provide display class for hardware driver");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef _SYSFS_DISPLAY_H_
+#define _SYSFS_DISPLAY_H_
+
+#include <linux/device.h>
+
+extern struct class *display_class;
+
+int spacemit_dpu_sysfs_init(struct device *dev);
+int spacemit_dsi_sysfs_init(struct device *dev);
+int spacemit_dphy_sysfs_init(struct device *dev);
+int spacemit_mipi_panel_sysfs_init(struct device *dev);
+
+#endif
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/sysfs.h>
+
+#include "../spacemit_lib.h"
+#include "../spacemit_dphy.h"
+#include "sysfs_display.h"
+
+
+
+int spacemit_dphy_sysfs_init(struct device *dev)
+{
+ int rc = 0;
+/*
+ rc = sysfs_create_groups(&dev->kobj, dphy_groups);
+ if (rc)
+ pr_err("create dphy attr node failed, rc=%d\n", rc);
+*/
+ return rc;
+}
+EXPORT_SYMBOL(spacemit_dphy_sysfs_init);
+
+
+MODULE_DESCRIPTION("Provide mipi dsi phy attribute nodes for userspace");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sysfs.h>
+#include <linux/timer.h>
+#include <linux/timex.h>
+#include <linux/rtc.h>
+
+#include "../spacemit_lib.h"
+#include "../spacemit_dpu.h"
+#include "../spacemit_mipi_panel.h"
+#include "sysfs_display.h"
+
+#ifdef CONFIG_PM
+static ssize_t spacemit_dpu_get_enable_auto_fc(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "enable_auto_fc = %d %d\n", dpu->enable_auto_fc, dpu->dev->power.runtime_status);
+}
+#endif
+
+#ifdef CONFIG_PM
+static ssize_t spacemit_dpu_set_enable_auto_fc(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ int enable_auto_fc = 0;
+ int ret = 0;
+
+ if (dpu->dev->power.runtime_status != RPM_SUSPENDED) {
+ pr_err("set dpu_enable_auto_fc only support when screen off!\n");
+ return -EINVAL;
+ }
+
+ ret = sscanf(buf, "%d\n", &enable_auto_fc);
+ if ((ret != 1) || (enable_auto_fc < 0) || (enable_auto_fc > 1)) {
+ pr_err("Wrong parameter! Please echo 0 or 1\n");
+ return -EINVAL;
+ }
+
+ if (enable_auto_fc == 0) {
+ dpu->new_mclk = DPU_MCLK_DEFAULT;
+ if (dpu->core && dpu->core->update_clk)
+ dpu->core->update_clk(dpu, dpu->new_mclk);
+ }
+
+ dpu->enable_auto_fc = enable_auto_fc;
+
+ return count;
+}
+#endif
+
+static ssize_t spacemit_dpu_get_enable_dump_reg(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "enable_dump_reg = %d\n", dpu->enable_dump_reg);
+}
+
+static ssize_t spacemit_dpu_set_enable_dump_reg(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ int enable_dump_reg = 0;
+ int ret = 0;
+
+ ret = sscanf(buf, "%d\n", &enable_dump_reg);
+ if ((ret != 1) || (enable_dump_reg < 0) || (enable_dump_reg > 1)) {
+ pr_err("Wrong parameter! Please echo 0 or 1\n");
+ return -EINVAL;
+ }
+
+ dpu->enable_dump_reg = enable_dump_reg;
+
+ return count;
+}
+
+static ssize_t spacemit_dpu_get_enable_dump_fps(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+
+ return snprintf(buf, PAGE_SIZE, "enable_dump_fps = %d\n", dpu->enable_dump_fps);
+}
+
+static ssize_t spacemit_dpu_set_enable_dump_fps(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct spacemit_dpu *dpu = dev_get_drvdata(dev);
+ int enable_dump_fps = 0;
+ int ret = 0;
+
+ ret = sscanf(buf, "%d\n", &enable_dump_fps);
+ if ((ret != 1) || (enable_dump_fps < 0) || (enable_dump_fps > 1)) {
+ pr_err("Wrong parameter! Please echo 0 or 1\n");
+ return -EINVAL;
+ }
+
+ dpu->enable_dump_fps = enable_dump_fps;
+
+ return count;
+}
+
+static DEVICE_ATTR(dpu_enable_dump_fps, S_IRUGO | S_IWUSR, spacemit_dpu_get_enable_dump_fps, spacemit_dpu_set_enable_dump_fps);
+static DEVICE_ATTR(dpu_enable_dump_reg, S_IRUGO | S_IWUSR, spacemit_dpu_get_enable_dump_reg, spacemit_dpu_set_enable_dump_reg);
+#ifdef CONFIG_PM
+static DEVICE_ATTR(dpu_enable_auto_fc, S_IRUGO | S_IWUSR, spacemit_dpu_get_enable_auto_fc, spacemit_dpu_set_enable_auto_fc);
+#endif
+
+int spacemit_dpu_sysfs_init(struct device *dev)
+{
+
+ int ret = 0;
+
+ ret = device_create_file(dev, &dev_attr_dpu_enable_dump_reg);
+ if (ret)
+ DRM_ERROR("failed to create device file: enable_dump_reg\n");
+ else
+ DRM_DEBUG("create device file enable_dump_reg\n");
+
+ ret = device_create_file(dev, &dev_attr_dpu_enable_dump_fps);
+ if (ret)
+ DRM_ERROR("failed to create device file: enable_dump_fps\n");
+ else
+ DRM_DEBUG("create device file enable_dump_fps\n");
+#ifdef CONFIG_PM
+ ret = device_create_file(dev, &dev_attr_dpu_enable_auto_fc);
+ if (ret)
+ DRM_ERROR("failed to create device file: enable_auto_fc\n");
+ else
+ DRM_DEBUG("create device file enable_auto_fc\n");
+#endif
+ return 0;
+}
+EXPORT_SYMBOL(spacemit_dpu_sysfs_init);
+
+MODULE_DESCRIPTION("Provide dpu attribute nodes for userspace");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include "../spacemit_mipi_panel.h"
+#include "../spacemit_dsi.h"
+#include "../spacemit_dpu.h"
+#include "sysfs_display.h"
+
+
+int spacemit_dsi_sysfs_init(struct device *dev)
+{
+
+ return 0;
+}
+EXPORT_SYMBOL(spacemit_dsi_sysfs_init);
+
+MODULE_DESCRIPTION("Provide mipi dsi attribute nodes for userspace");
+MODULE_LICENSE("GPL v2");
+
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sysfs.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <video/videomode.h>
+
+#include "../spacemit_lib.h"
+#include "../spacemit_mipi_panel.h"
+#include "sysfs_display.h"
+
+
+int spacemit_mipi_panel_sysfs_init(struct device *dev)
+{
+ return 0;
+}
+EXPORT_SYMBOL(spacemit_mipi_panel_sysfs_init);
+
+MODULE_DESCRIPTION("Provide panel attribute nodes for userspace");
+MODULE_LICENSE("GPL v2");
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Spacemit Co., Ltd.
+ *
+ */
+
+#ifndef __SPACEMIT_PANEL_H__
+#define __SPACEMIT_PANEL_H__
+
+#include <linux/notifier.h>
+
+/* complete the definition of DRM Macros */
+enum{
+ DRM_PANEL_EARLY_EVENT_BLANK = 0,
+ DRM_PANEL_EVENT_BLANK,
+ DRM_PANEL_BLANK_UNBLANK,
+ DRM_PANEL_BLANK_POWERDOWN,
+};
+
+extern int spacemit_drm_register_client(struct notifier_block *nb);
+extern int spacemit_drm_unregister_client(struct notifier_block *nb);
+
+#endif