diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index b568dc209890..a66ecbc33b97 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -117,6 +117,20 @@ enum vop2_win_dly_mode { #define VOP2_PD_DSC_8K BIT(5) #define VOP2_PD_DSC_4K BIT(6) +/* + * vop2 submem power gate, + * should be all none zero, 0 will be + * treat as invalid; + */ +#define VOP2_MEM_PG_VP0 BIT(0) +#define VOP2_MEM_PG_VP1 BIT(1) +#define VOP2_MEM_PG_VP2 BIT(2) +#define VOP2_MEM_PG_VP3 BIT(3) +#define VOP2_MEM_PG_DB0 BIT(4) +#define VOP2_MEM_PG_DB1 BIT(5) +#define VOP2_MEM_PG_DB2 BIT(6) +#define VOP2_MEM_PG_WB BIT(7) + #define DSP_BG_SWAP 0x1 #define DSP_RB_SWAP 0x2 #define DSP_RG_SWAP 0x4 @@ -1027,6 +1041,7 @@ struct vop2_data { uint8_t nr_gammas; uint8_t nr_conns; uint8_t nr_pds; + uint8_t nr_mem_pgs; bool delayed_pd; const struct vop_intr *axi_intr; const struct vop2_ctrl *ctrl; @@ -1039,6 +1054,7 @@ struct vop2_data { const struct vop2_wb_data *wb; const struct vop2_layer_data *layer; const struct vop2_power_domain_data *pd; + const struct vop2_power_domain_data *mem_pg; const struct vop_csc_table *csc_table; const struct vop_hdr_table *hdr_table; const struct vop_grf_ctrl *sys_grf; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index b464f7126b08..982ab6f4ca8e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -655,6 +655,7 @@ struct vop2 { struct regmap *sys_grf; struct regmap *vo0_grf; struct regmap *vo1_grf; + struct regmap *pmu; /* physical map length of vop2 register */ uint32_t len; @@ -2946,7 +2947,7 @@ static void rk3588_vop2_regsbak(struct vop2 *vop2) /* * No need to backup DSC/GAMMA_LUT/BPP_LUT/MMU */ - for (i = 0; i < (RK3588_DSC_8K_PPS0_3 >> 2); i++) + for (i = 0; i < (0x2000 >> 2); i++) vop2->regsbak[i] = base[i]; for (i = 0; i < vop2_data->nr_dscs; i++) { @@ -7071,7 +7072,7 @@ static irqreturn_t vop2_isr(int irq, void *data) do { \ if (active_irqs & x##_INTR) {\ if (x##_INTR == POST_BUF_EMPTY_INTR) \ - DRM_DEV_ERROR_RATELIMITED(vop2->dev, #x " irq err at vp%d\n", vp->id); \ + printk(KERN_DEBUG #x " irq err at vp%d\n", vp->id); \ else \ DRM_DEV_ERROR_RATELIMITED(vop2->dev, #x " irq err\n"); \ active_irqs &= ~x##_INTR; \ @@ -7922,6 +7923,7 @@ static int vop2_bind(struct device *dev, struct device *master, void *data) vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); vop2->grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf"); vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf"); + vop2->pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu"); vop2->hclk = devm_clk_get(vop2->dev, "hclk_vop"); if (IS_ERR(vop2->hclk)) { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c index 612f4af60a17..e965e1e77afe 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c +++ b/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c @@ -1974,13 +1974,13 @@ static const struct vop2_power_domain_data rk3588_vop_pd_data[] = { { .id = VOP2_PD_CLUSTER2, .parent_id = VOP2_PD_CLUSTER0, - .regs = &rk3588_cluster0_pd_regs, + .regs = &rk3588_cluster2_pd_regs, }, { .id = VOP2_PD_CLUSTER3, .parent_id = VOP2_PD_CLUSTER0, - .regs = &rk3588_cluster1_pd_regs, + .regs = &rk3588_cluster3_pd_regs, }, { @@ -1999,6 +1999,98 @@ static const struct vop2_power_domain_data rk3588_vop_pd_data[] = { }, }; +const struct vop2_power_domain_regs rk3588_mem_pg_vp0_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON1, 0x1, 15), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 19), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_vp1_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 0), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 20), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_vp2_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 1), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 21), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_vp3_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 2), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 22), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_db0_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 3), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 23), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_db1_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 4), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 24), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_db2_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 5), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 25), +}; + +const struct vop2_power_domain_regs rk3588_mem_pg_wb_regs = { + .pd = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_CON2, 0x1, 6), + .status = VOP_REG(RK3588_PMU_SUBMEM_PWR_GATE_STATUS, 0x1, 26), +}; + +/* + * All power gates will power on when PD_VOP is turn on. + * Corresponding mem_pwr_ack_bypass bit should be enabled + * if power gate powe down before PD_VOP. + * power gates take effect immediately, this means there + * is no synchronization between vop frame scanout, so + * we can only enable a power gate before we enable + * a module, and turn off power gate after the module + * is actually disabled. + */ +static const struct vop2_power_domain_data rk3588_vop_mem_pg_data[] = { + { + .id = VOP2_MEM_PG_VP0, + .regs = &rk3588_mem_pg_vp0_regs, + }, + + { + .id = VOP2_MEM_PG_VP1, + .regs = &rk3588_mem_pg_vp1_regs, + }, + + { + .id = VOP2_MEM_PG_VP2, + .regs = &rk3588_mem_pg_vp2_regs, + }, + + { + .id = VOP2_MEM_PG_VP3, + .regs = &rk3588_mem_pg_vp3_regs, + }, + + { + .id = VOP2_MEM_PG_DB0, + .regs = &rk3588_mem_pg_db0_regs, + }, + + { + .id = VOP2_MEM_PG_DB1, + .regs = &rk3588_mem_pg_db1_regs, + }, + + { + .id = VOP2_MEM_PG_DB2, + .regs = &rk3588_mem_pg_db2_regs, + }, + + { + .id = VOP2_MEM_PG_WB, + .regs = &rk3588_mem_pg_wb_regs, + }, +}; + /* * rk3588 vop with 4 cluster, 4 esmart win. * Every cluster can work as 4K win or split into two win. @@ -2511,6 +2603,8 @@ static const struct vop2_data rk3588_vop = { .win_size = ARRAY_SIZE(rk3588_vop_win_data), .pd = rk3588_vop_pd_data, .nr_pds = ARRAY_SIZE(rk3588_vop_pd_data), + .mem_pg = rk3588_vop_mem_pg_data, + .nr_mem_pgs = ARRAY_SIZE(rk3588_vop_mem_pg_data), }; static const struct of_device_id vop2_dt_match[] = { diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h index b2000d083c54..b53aac74182a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h @@ -1613,4 +1613,11 @@ #define RK3588_GRF_VOP_CON2 0x08 #define RK3588_GRF_VO1_CON0 0x00 + +#define RK3588_PMU_PWR_GATE_CON1 0x150 +#define RK3588_PMU_SUBMEM_PWR_GATE_CON1 0x1B4 +#define RK3588_PMU_SUBMEM_PWR_GATE_CON2 0x1B8 +#define RK3588_PMU_SUBMEM_PWR_GATE_STATUS 0x1BC +#define RK3588_PMU_BISR_STATUS5 0x294 + #endif /* _ROCKCHIP_VOP_REG_H */