Loading Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +4 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,10 @@ Optional properties: [1] for details. - qcom,msm-bus,vectors-KBps: Required if qcom,msm-bus,name is specified. See [1] for an explanation of the data format. - mboxes: Mailbox tuple containing QMP mailbox phandle and channel identifier. If this is specified, then a QMP message should be sent to enable the GDSC instead of setting SW_COLLAPSE=0. [1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt Loading arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -211,6 +211,7 @@ qcom,skip-disable; qcom,gds-timeout = <500>; qcom,clk-dis-wait-val = <8>; mboxes = <&qmp_aop 0>; status = "disabled"; }; Loading arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ qcom,initial-pwrlevel = <5>; qcom,gpu-quirk-secvid-set-once; qcom,gpu-quirk-cx-gdsc; qcom,idle-timeout = <80>; //msecs qcom,no-nap; Loading drivers/clk/qcom/gdsc-regulator.c +103 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/of.h> #include <linux/mailbox_client.h> #include <linux/msm-bus.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> Loading @@ -28,6 +29,7 @@ #include <linux/reset.h> #include <linux/mfd/syscon.h> #include <linux/clk/qcom.h> #include <linux/mailbox/qmp.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> Loading @@ -52,6 +54,8 @@ /* Timeout Delay */ #define TIMEOUT_US 100 #define MBOX_TOUT_MS 100 struct gdsc { struct regulator_dev *rdev; struct regulator_desc rdesc; Loading @@ -64,6 +68,8 @@ struct gdsc { struct regulator *parent_regulator; struct reset_control **reset_clocks; struct msm_bus_scale_pdata *bus_pdata; struct mbox_client mbox_client; struct mbox_chan *mbox; u32 bus_handle; bool toggle_mem; bool toggle_periph; Loading @@ -73,6 +79,7 @@ struct gdsc { bool force_root_en; bool no_status_check_on_disable; bool skip_disable; bool bypass_skip_disable; bool is_gdsc_enabled; bool allow_clear; bool reset_aon; Loading Loading @@ -218,6 +225,35 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) return is_enabled; } #define MAX_LEN 96 static int gdsc_qmp_enable(struct gdsc *sc) { char buf[MAX_LEN] = "{class: clock, res: gpu_noc_wa}"; struct qmp_pkt pkt; uint32_t regval; int ret; regmap_read(sc->regmap, REG_OFFSET, ®val); if (!(regval & SW_COLLAPSE_MASK)) { /* * Do not enable via a QMP request if the GDSC is already * enabled by software. */ return 0; } pkt.size = MAX_LEN; pkt.data = buf; ret = mbox_send_message(sc->mbox, &pkt); if (ret < 0) dev_err(&sc->rdev->dev, "qmp message send failed, ret=%d\n", ret); return ret; } static int gdsc_enable(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); Loading Loading @@ -308,9 +344,15 @@ static int gdsc_enable(struct regulator_dev *rdev) gdsc_mb(sc); } if (sc->mbox) { ret = gdsc_qmp_enable(sc); if (ret < 0) goto end; } else { regmap_read(sc->regmap, REG_OFFSET, ®val); regval &= ~SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); } /* Wait for 8 XO cycles before polling the status bit. */ gdsc_mb(sc); Loading Loading @@ -426,7 +468,7 @@ static int gdsc_disable(struct regulator_dev *rdev) /* Delay to account for staggered memory powerdown. */ udelay(1); if (sc->skip_disable) { if (sc->skip_disable && !sc->bypass_skip_disable) { /* * Don't change the GDSCR register state on disable. AOP will * handle this during system sleep. Loading Loading @@ -497,6 +539,12 @@ static unsigned int gdsc_get_mode(struct regulator_dev *rdev) uint32_t regval; int ret; if (sc->skip_disable) { if (sc->bypass_skip_disable) return REGULATOR_MODE_IDLE; return REGULATOR_MODE_NORMAL; } mutex_lock(&gdsc_seq_lock); if (sc->parent_regulator) { Loading Loading @@ -556,6 +604,23 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) mutex_lock(&gdsc_seq_lock); if (sc->skip_disable) { switch (mode) { case REGULATOR_MODE_IDLE: sc->bypass_skip_disable = true; break; case REGULATOR_MODE_NORMAL: sc->bypass_skip_disable = false; break; default: ret = -EINVAL; break; } mutex_unlock(&gdsc_seq_lock); return ret; } if (sc->parent_regulator) { ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); Loading Loading @@ -817,6 +882,23 @@ static int gdsc_probe(struct platform_device *pdev) sc->is_bus_enabled = true; } if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { sc->mbox_client.dev = &pdev->dev; sc->mbox_client.tx_block = true; sc->mbox_client.tx_tout = MBOX_TOUT_MS; sc->mbox_client.knows_txdone = false; sc->mbox = mbox_request_channel(&sc->mbox_client, 0); if (IS_ERR(sc->mbox)) { ret = PTR_ERR(sc->mbox); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "mailbox channel request failed, ret=%d\n", ret); sc->mbox = NULL; goto err; } } sc->rdesc.id = atomic_inc_return(&gdsc_count); sc->rdesc.ops = &gdsc_ops; sc->rdesc.type = REGULATOR_VOLTAGE; Loading Loading @@ -862,6 +944,17 @@ static int gdsc_probe(struct platform_device *pdev) REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST; } if (sc->skip_disable) { /* * If the disable skipping feature is allowed, then use mode * control to enable and disable the feature at runtime instead * of using it to enable and disable hardware triggering. */ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; init_data->constraints.valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE; } if (!sc->toggle_logic) { sc->reset_count = of_property_count_strings(pdev->dev.of_node, "reset-names"); Loading Loading @@ -955,6 +1048,9 @@ static int gdsc_probe(struct platform_device *pdev) return 0; err: if (sc->mbox) mbox_free_channel(sc->mbox); if (sc->bus_handle) { if (sc->is_bus_enabled) msm_bus_scale_client_update_request(sc->bus_handle, 0); Loading @@ -970,6 +1066,9 @@ static int gdsc_remove(struct platform_device *pdev) regulator_unregister(sc->rdev); if (sc->mbox) mbox_free_channel(sc->mbox); if (sc->bus_handle) { if (sc->is_bus_enabled) msm_bus_scale_client_update_request(sc->bus_handle, 0); Loading Loading
Documentation/devicetree/bindings/regulator/gdsc-regulator.txt +4 −0 Original line number Diff line number Diff line Loading @@ -76,6 +76,10 @@ Optional properties: [1] for details. - qcom,msm-bus,vectors-KBps: Required if qcom,msm-bus,name is specified. See [1] for an explanation of the data format. - mboxes: Mailbox tuple containing QMP mailbox phandle and channel identifier. If this is specified, then a QMP message should be sent to enable the GDSC instead of setting SW_COLLAPSE=0. [1]: Documentation/devicetree/bindings/arm/msm/msm_bus.txt Loading
arch/arm64/boot/dts/qcom/sm8150-gdsc.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -211,6 +211,7 @@ qcom,skip-disable; qcom,gds-timeout = <500>; qcom,clk-dis-wait-val = <8>; mboxes = <&qmp_aop 0>; status = "disabled"; }; Loading
arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +1 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ qcom,initial-pwrlevel = <5>; qcom,gpu-quirk-secvid-set-once; qcom,gpu-quirk-cx-gdsc; qcom,idle-timeout = <80>; //msecs qcom,no-nap; Loading
drivers/clk/qcom/gdsc-regulator.c +103 −4 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/of.h> #include <linux/mailbox_client.h> #include <linux/msm-bus.h> #include <linux/platform_device.h> #include <linux/regulator/driver.h> Loading @@ -28,6 +29,7 @@ #include <linux/reset.h> #include <linux/mfd/syscon.h> #include <linux/clk/qcom.h> #include <linux/mailbox/qmp.h> #include <dt-bindings/regulator/qcom,rpmh-regulator.h> Loading @@ -52,6 +54,8 @@ /* Timeout Delay */ #define TIMEOUT_US 100 #define MBOX_TOUT_MS 100 struct gdsc { struct regulator_dev *rdev; struct regulator_desc rdesc; Loading @@ -64,6 +68,8 @@ struct gdsc { struct regulator *parent_regulator; struct reset_control **reset_clocks; struct msm_bus_scale_pdata *bus_pdata; struct mbox_client mbox_client; struct mbox_chan *mbox; u32 bus_handle; bool toggle_mem; bool toggle_periph; Loading @@ -73,6 +79,7 @@ struct gdsc { bool force_root_en; bool no_status_check_on_disable; bool skip_disable; bool bypass_skip_disable; bool is_gdsc_enabled; bool allow_clear; bool reset_aon; Loading Loading @@ -218,6 +225,35 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) return is_enabled; } #define MAX_LEN 96 static int gdsc_qmp_enable(struct gdsc *sc) { char buf[MAX_LEN] = "{class: clock, res: gpu_noc_wa}"; struct qmp_pkt pkt; uint32_t regval; int ret; regmap_read(sc->regmap, REG_OFFSET, ®val); if (!(regval & SW_COLLAPSE_MASK)) { /* * Do not enable via a QMP request if the GDSC is already * enabled by software. */ return 0; } pkt.size = MAX_LEN; pkt.data = buf; ret = mbox_send_message(sc->mbox, &pkt); if (ret < 0) dev_err(&sc->rdev->dev, "qmp message send failed, ret=%d\n", ret); return ret; } static int gdsc_enable(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); Loading Loading @@ -308,9 +344,15 @@ static int gdsc_enable(struct regulator_dev *rdev) gdsc_mb(sc); } if (sc->mbox) { ret = gdsc_qmp_enable(sc); if (ret < 0) goto end; } else { regmap_read(sc->regmap, REG_OFFSET, ®val); regval &= ~SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); } /* Wait for 8 XO cycles before polling the status bit. */ gdsc_mb(sc); Loading Loading @@ -426,7 +468,7 @@ static int gdsc_disable(struct regulator_dev *rdev) /* Delay to account for staggered memory powerdown. */ udelay(1); if (sc->skip_disable) { if (sc->skip_disable && !sc->bypass_skip_disable) { /* * Don't change the GDSCR register state on disable. AOP will * handle this during system sleep. Loading Loading @@ -497,6 +539,12 @@ static unsigned int gdsc_get_mode(struct regulator_dev *rdev) uint32_t regval; int ret; if (sc->skip_disable) { if (sc->bypass_skip_disable) return REGULATOR_MODE_IDLE; return REGULATOR_MODE_NORMAL; } mutex_lock(&gdsc_seq_lock); if (sc->parent_regulator) { Loading Loading @@ -556,6 +604,23 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) mutex_lock(&gdsc_seq_lock); if (sc->skip_disable) { switch (mode) { case REGULATOR_MODE_IDLE: sc->bypass_skip_disable = true; break; case REGULATOR_MODE_NORMAL: sc->bypass_skip_disable = false; break; default: ret = -EINVAL; break; } mutex_unlock(&gdsc_seq_lock); return ret; } if (sc->parent_regulator) { ret = regulator_set_voltage(sc->parent_regulator, RPMH_REGULATOR_LEVEL_LOW_SVS, INT_MAX); Loading Loading @@ -817,6 +882,23 @@ static int gdsc_probe(struct platform_device *pdev) sc->is_bus_enabled = true; } if (of_find_property(pdev->dev.of_node, "mboxes", NULL)) { sc->mbox_client.dev = &pdev->dev; sc->mbox_client.tx_block = true; sc->mbox_client.tx_tout = MBOX_TOUT_MS; sc->mbox_client.knows_txdone = false; sc->mbox = mbox_request_channel(&sc->mbox_client, 0); if (IS_ERR(sc->mbox)) { ret = PTR_ERR(sc->mbox); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "mailbox channel request failed, ret=%d\n", ret); sc->mbox = NULL; goto err; } } sc->rdesc.id = atomic_inc_return(&gdsc_count); sc->rdesc.ops = &gdsc_ops; sc->rdesc.type = REGULATOR_VOLTAGE; Loading Loading @@ -862,6 +944,17 @@ static int gdsc_probe(struct platform_device *pdev) REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST; } if (sc->skip_disable) { /* * If the disable skipping feature is allowed, then use mode * control to enable and disable the feature at runtime instead * of using it to enable and disable hardware triggering. */ init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE; init_data->constraints.valid_modes_mask = REGULATOR_MODE_NORMAL | REGULATOR_MODE_IDLE; } if (!sc->toggle_logic) { sc->reset_count = of_property_count_strings(pdev->dev.of_node, "reset-names"); Loading Loading @@ -955,6 +1048,9 @@ static int gdsc_probe(struct platform_device *pdev) return 0; err: if (sc->mbox) mbox_free_channel(sc->mbox); if (sc->bus_handle) { if (sc->is_bus_enabled) msm_bus_scale_client_update_request(sc->bus_handle, 0); Loading @@ -970,6 +1066,9 @@ static int gdsc_remove(struct platform_device *pdev) regulator_unregister(sc->rdev); if (sc->mbox) mbox_free_channel(sc->mbox); if (sc->bus_handle) { if (sc->is_bus_enabled) msm_bus_scale_client_update_request(sc->bus_handle, 0); Loading