diff --git a/arch/arm64/boot/dts/rockchip/rk3562.dtsi b/arch/arm64/boot/dts/rockchip/rk3562.dtsi index 0f2c36377e52..a6d904fe01b1 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562.dtsi @@ -899,26 +899,51 @@ reg = <0x0 0xfee03800 0x0 0x20>; }; + shaping_dam2ddr: shaping@fee03888 { + compatible = "syscon"; + reg = <0x0 0xfee03888 0x0 0x4>; + }; + qos_mcu: qos@fee10000 { compatible = "syscon"; reg = <0x0 0xfee10000 0x0 0x20>; }; + shaping_mcu: shaping@fee10088 { + compatible = "syscon"; + reg = <0x0 0xfee10088 0x0 0x4>; + }; + qos_dft_apb: qos@fee10100 { compatible = "syscon"; reg = <0x0 0xfee10100 0x0 0x20>; }; + shaping_dft_apb: shaping@fee10188 { + compatible = "syscon"; + reg = <0x0 0xfee10188 0x0 0x4>; + }; + qos_gmac: qos@fee10200 { compatible = "syscon"; reg = <0x0 0xfee10200 0x0 0x20>; }; + shaping_gmac: shaping@fee10288 { + compatible = "syscon"; + reg = <0x0 0xfee10288 0x0 0x4>; + }; + qos_mac100: qos@fee10300 { compatible = "syscon"; reg = <0x0 0xfee10300 0x0 0x20>; }; + shaping_mac100: shaping@fee10388 { + compatible = "syscon"; + reg = <0x0 0xfee10388 0x0 0x4>; + }; + qos_dcf: qos@fee10400 { compatible = "syscon"; reg = <0x0 0xfee10400 0x0 0x20>; @@ -929,117 +954,233 @@ reg = <0x0 0xfee20000 0x0 0x20>; }; + shaping_cpu: shaping@fee20088 { + compatible = "syscon"; + reg = <0x0 0xfee20088 0x0 0x4>; + }; + qos_daplite_apb: qos@fee20100 { compatible = "syscon"; reg = <0x0 0xfee20100 0x0 0x20>; }; + shaping_daplite_apb: shaping@fee20188 { + compatible = "syscon"; + reg = <0x0 0xfee20188 0x0 0x4>; + }; + qos_gpu: qos@fee30000 { compatible = "syscon"; reg = <0x0 0xfee30000 0x0 0x20>; priority-init = <0x202>; }; + shaping_gpu: shaping@fee30088 { + compatible = "syscon"; + reg = <0x0 0xfee30088 0x0 0x4>; + }; + qos_npu: qos@fee40000 { compatible = "syscon"; reg = <0x0 0xfee40000 0x0 0x20>; }; + shaping_npu: shaping@fee40088 { + compatible = "syscon"; + reg = <0x0 0xfee40088 0x0 0x4>; + }; + qos_rkvdec: qos@fee50000 { compatible = "syscon"; reg = <0x0 0xfee50000 0x0 0x20>; }; + shaping_rkvdec: shaping@fee50088 { + compatible = "syscon"; + reg = <0x0 0xfee50088 0x0 0x4>; + }; + qos_vepu: qos@fee60000 { compatible = "syscon"; reg = <0x0 0xfee60000 0x0 0x20>; }; + shaping_vepu: shaping@fee60088 { + compatible = "syscon"; + reg = <0x0 0xfee60088 0x0 0x4>; + }; + qos_isp: qos@fee70000 { compatible = "syscon"; reg = <0x0 0xfee70000 0x0 0x20>; }; + shaping_isp: shaping@fee70088 { + compatible = "syscon"; + reg = <0x0 0xfee70088 0x0 0x4>; + }; + qos_vicap: qos@fee70100 { compatible = "syscon"; reg = <0x0 0xfee70100 0x0 0x20>; }; + shaping_vicap: shaping@fee70188 { + compatible = "syscon"; + reg = <0x0 0xfee70188 0x0 0x4>; + }; + qos_vop: qos@fee80000 { compatible = "syscon"; reg = <0x0 0xfee80000 0x0 0x20>; }; + shaping_vop: shaping@fee80088 { + compatible = "syscon"; + reg = <0x0 0xfee80088 0x0 0x4>; + }; + qos_jpeg: qos@fee90000 { compatible = "syscon"; reg = <0x0 0xfee90000 0x0 0x20>; }; + shaping_jpeg: shaping@fee90088 { + compatible = "syscon"; + reg = <0x0 0xfee90088 0x0 0x4>; + }; + qos_rga_rd: qos@fee90100 { compatible = "syscon"; reg = <0x0 0xfee90100 0x0 0x20>; }; + shaping_rga_rd: shaping@fee90188 { + compatible = "syscon"; + reg = <0x0 0xfee90188 0x0 0x4>; + }; + qos_rga_wr: qos@fee90200 { compatible = "syscon"; reg = <0x0 0xfee90200 0x0 0x20>; }; + shaping_rga_wr: shaping@fee90288 { + compatible = "syscon"; + reg = <0x0 0xfee90288 0x0 0x4>; + }; + qos_pcie: qos@feea0000 { compatible = "syscon"; reg = <0x0 0xfeea0000 0x0 0x20>; }; + shaping_pcie: shaping@feea0088 { + compatible = "syscon"; + reg = <0x0 0xfeea0088 0x0 0x4>; + shaping-init = <0x5>; + }; + qos_usb3: qos@feea0100 { compatible = "syscon"; reg = <0x0 0xfeea0100 0x0 0x20>; }; + shaping_usb3: shaping@feea0188 { + compatible = "syscon"; + reg = <0x0 0xfeea0188 0x0 0x4>; + }; + qos_crypto_apb: qos@feeb0000 { compatible = "syscon"; reg = <0x0 0xfeeb0000 0x0 0x20>; }; + shaping_crypto_apb: shaping@feeb0088 { + compatible = "syscon"; + reg = <0x0 0xfeeb0088 0x0 0x4>; + }; + qos_crypto: qos@feeb0100 { compatible = "syscon"; reg = <0x0 0xfeeb0100 0x0 0x20>; }; + shaping_crypto: shaping@feeb0188 { + compatible = "syscon"; + reg = <0x0 0xfeeb0188 0x0 0x4>; + }; + qos_dmac: qos@feeb0200 { compatible = "syscon"; reg = <0x0 0xfeeb0200 0x0 0x20>; }; + shaping_dmac: shaping@feeb0288 { + compatible = "syscon"; + reg = <0x0 0xfeeb0288 0x0 0x4>; + }; + qos_emmc: qos@feeb0300 { compatible = "syscon"; reg = <0x0 0xfeeb0300 0x0 0x20>; }; + shaping_emmc: shaping@feeb0388 { + compatible = "syscon"; + reg = <0x0 0xfeeb0388 0x0 0x4>; + }; + qos_fspi: qos@feeb0400 { compatible = "syscon"; reg = <0x0 0xfeeb0400 0x0 0x20>; }; + shaping_fspi: shaping@feeb0488 { + compatible = "syscon"; + reg = <0x0 0xfeeb0488 0x0 0x4>; + }; + qos_rkdma: qos@feeb0500 { compatible = "syscon"; reg = <0x0 0xfeeb0500 0x0 0x20>; }; + shaping_rkdma: shaping@feeb0588 { + compatible = "syscon"; + reg = <0x0 0xfeeb0588 0x0 0x4>; + }; + qos_sdmmc0: qos@feeb0600 { compatible = "syscon"; reg = <0x0 0xfeeb0600 0x0 0x20>; }; + shaping_sdmmc0: shaping@feeb0688 { + compatible = "syscon"; + reg = <0x0 0xfeeb0688 0x0 0x4>; + }; + qos_sdmmc1: qos@feeb0700 { compatible = "syscon"; reg = <0x0 0xfeeb0700 0x0 0x20>; }; + shaping_sdmmc1: shaping@feeb0788 { + compatible = "syscon"; + reg = <0x0 0xfeeb0788 0x0 0x4>; + }; + qos_usb2: qos@feeb0800 { compatible = "syscon"; reg = <0x0 0xfeeb0800 0x0 0x20>; }; + shaping_usb2: shaping@feeb0888 { + compatible = "syscon"; + reg = <0x0 0xfeeb0888 0x0 0x4>; + }; + pmu_grf: syscon@ff010000 { compatible = "rockchip,rk3562-pmu-grf", "syscon", "simple-mfd"; reg = <0x0 0xff010000 0x0 0x10000>; @@ -1250,16 +1391,19 @@ pd_gpu@RK3562_PD_GPU { reg = ; pm_qos = <&qos_gpu>; + pm_shaping = <&shaping_gpu>; }; /* These power domains are grouped by VD_NPU */ pd_npu@RK3562_PD_NPU { reg = ; pm_qos = <&qos_npu>; + pm_shaping = <&shaping_npu>; }; /* These power domains are grouped by VD_LOGIC */ pd_vdpu@RK3562_PD_VDPU { reg = ; pm_qos = <&qos_rkvdec>; + pm_shaping = <&shaping_rkvdec>; }; pd_vi@RK3562_PD_VI { reg = ; @@ -1267,10 +1411,13 @@ #size-cells = <0>; pm_qos = <&qos_isp>, <&qos_vicap>; + pm_shaping = <&shaping_isp>, + <&shaping_vicap>; pd_vepu@RK3562_PD_VEPU { reg = ; pm_qos = <&qos_vepu>; + pm_shaping = <&shaping_vepu>; }; }; pd_vo@RK3562_PD_VO { @@ -1278,18 +1425,24 @@ #address-cells = <1>; #size-cells = <0>; pm_qos = <&qos_vop>; + pm_shaping= <&shaping_vop>; pd_rga@RK3562_PD_RGA { reg = ; pm_qos = <&qos_rga_rd>, <&qos_rga_wr>, <&qos_jpeg>; + pm_shaping = <&shaping_rga_rd>, + <&shaping_rga_wr>, + <&shaping_jpeg>; }; }; pd_php@RK3562_PD_PHP { reg = ; pm_qos = <&qos_pcie>, <&qos_usb3>; + pm_shaping = <&shaping_pcie>, + <&shaping_usb3>; }; }; }; diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index b6d59251da8c..17a12c1dae39 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -95,19 +95,26 @@ struct rockchip_pmu_info { #define QOS_SATURATION 0x14 #define QOS_EXTCONTROL 0x18 +#define SHAPING_NBPKTMAX0 0x0 + struct rockchip_pm_domain { struct generic_pm_domain genpd; const struct rockchip_domain_info *info; struct rockchip_pmu *pmu; int num_qos; + int num_shaping; struct regmap **qos_regmap; + struct regmap **shaping_regmap; u32 *qos_save_regs[MAX_QOS_REGS_NUM]; + u32 *shaping_save_regs; bool *qos_is_need_init[MAX_QOS_REGS_NUM]; + bool *shaping_is_need_init; int num_clks; struct clk_bulk_data *clks; bool is_ignore_pwr; bool is_qos_saved; bool is_qos_need_init; + bool is_shaping_need_init; struct regulator *supply; }; @@ -560,6 +567,45 @@ int rockchip_pmu_idle_request(struct device *dev, bool idle) } EXPORT_SYMBOL(rockchip_pmu_idle_request); +static int rockchip_pmu_save_shaping(struct rockchip_pm_domain *pd) +{ + int i; + + for (i = 0; i < pd->num_shaping; i++) + regmap_read(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, + &pd->shaping_save_regs[i]); + + return 0; +} + +static int rockchip_pmu_restore_shaping(struct rockchip_pm_domain *pd) +{ + int i; + + for (i = 0; i < pd->num_shaping; i++) + regmap_write(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, + pd->shaping_save_regs[i]); + + return 0; +} + +static void rockchip_pmu_init_shaping(struct rockchip_pm_domain *pd) +{ + int i; + + if (!pd->is_shaping_need_init) + return; + + for (i = 0; i < pd->num_shaping; i++) + if (pd->shaping_is_need_init[i]) + regmap_write(pd->shaping_regmap[i], SHAPING_NBPKTMAX0, + pd->shaping_save_regs[i]); + + kfree(pd->shaping_is_need_init); + pd->shaping_is_need_init = NULL; + pd->is_shaping_need_init = false; +} + static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) { int i; @@ -581,7 +627,8 @@ static int rockchip_pmu_save_qos(struct rockchip_pm_domain *pd) QOS_EXTCONTROL, &pd->qos_save_regs[4][i]); } - return 0; + + return rockchip_pmu_save_shaping(pd); } static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) @@ -606,13 +653,15 @@ static int rockchip_pmu_restore_qos(struct rockchip_pm_domain *pd) pd->qos_save_regs[4][i]); } - return 0; + return rockchip_pmu_restore_shaping(pd); } static void rockchip_pmu_init_qos(struct rockchip_pm_domain *pd) { int i; + rockchip_pmu_init_shaping(pd); + if (!pd->is_qos_need_init) return; @@ -906,7 +955,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) if (pd->is_qos_saved) rockchip_pmu_restore_qos(pd); - if (pd->is_qos_need_init) + if (pd->is_qos_need_init || pd->is_shaping_need_init) rockchip_pmu_init_qos(pd); } @@ -1046,8 +1095,13 @@ static void rockchip_pd_qos_init(struct rockchip_pm_domain *pd) if (!pd->is_qos_need_init) { kfree(pd->qos_is_need_init[0]); pd->qos_is_need_init[0] = NULL; - return; } + if (!pd->is_shaping_need_init) { + kfree(pd->shaping_is_need_init); + pd->shaping_is_need_init = NULL; + } + if (!pd->is_qos_need_init && !pd->is_shaping_need_init) + return; is_pd_on = rockchip_pmu_domain_is_on(pd); if (is_pd_on) { @@ -1081,6 +1135,79 @@ static int rockchip_pd_add_alwasy_on_flag(struct rockchip_pm_domain *pd) return 0; } +static int rockchip_pd_of_get_shaping(struct rockchip_pm_domain *pd, + struct device_node *node) +{ + struct rockchip_pmu *pmu = pd->pmu; + struct device_node *shaping_node; + int num_shaping = 0, num_shaping_reg = 0; + int error, i; + u32 val; + + num_shaping = of_count_phandle_with_args(node, "pm_shaping", NULL); + + for (i = 0; i < num_shaping; i++) { + shaping_node = of_parse_phandle(node, "pm_shaping", i); + if (shaping_node && of_device_is_available(shaping_node)) + pd->num_shaping++; + of_node_put(shaping_node); + } + + if (pd->num_shaping > 0) { + pd->shaping_regmap = devm_kcalloc(pmu->dev, pd->num_shaping, + sizeof(*pd->shaping_regmap), + GFP_KERNEL); + if (!pd->shaping_regmap) + return -ENOMEM; + pd->shaping_save_regs = devm_kmalloc(pmu->dev, sizeof(u32) * + pd->num_shaping, + GFP_KERNEL); + if (!pd->shaping_save_regs) + return -ENOMEM; + pd->shaping_is_need_init = kcalloc(pd->num_shaping, sizeof(bool), + GFP_KERNEL); + if (!pd->shaping_is_need_init) + return -ENOMEM; + for (i = 0; i < num_shaping; i++) { + shaping_node = of_parse_phandle(node, "pm_shaping", i); + if (!shaping_node) { + error = -ENODEV; + goto err_free_init; + } + if (of_device_is_available(shaping_node)) { + pd->shaping_regmap[num_shaping_reg] = + syscon_node_to_regmap(shaping_node); + if (IS_ERR(pd->shaping_regmap[num_shaping_reg])) { + of_node_put(shaping_node); + error = -ENODEV; + goto err_free_init; + } + if (!of_property_read_u32(shaping_node, + "shaping-init", + &val)) { + pd->shaping_save_regs[i] = val; + pd->shaping_is_need_init[i] = true; + pd->is_shaping_need_init = true; + } + num_shaping_reg++; + } + of_node_put(shaping_node); + if (num_shaping_reg > pd->num_shaping) { + error = -EINVAL; + goto err_free_init; + } + } + } + + return 0; + +err_free_init: + kfree(pd->shaping_is_need_init); + pd->shaping_is_need_init = NULL; + + return error; +} + static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, struct device_node *node) { @@ -1258,6 +1385,10 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, } } + error = rockchip_pd_of_get_shaping(pd, node); + if (error) + goto err_unprepare_clocks; + if (pd->info->name) pd->genpd.name = pd->info->name; else