Quoting David Dai (2018-12-13 18:35:04) > The current clk-rpmh driver only supports on and off RPMh clock resources, > let's extend the current driver by add support for clocks that are managed > by a different type of RPMh resource known as Bus Clock Manager(BCM). > The BCM is a configurable shared resource aggregator that scales performance > based on a preset of frequency points. The Qualcomm IP Accelerator (IPA) clock > is an example of a resource that is managed by the BCM and this a requirement > from the IPA driver in order to scale its core clock. Please use this commit text instead: The clk-rpmh driver only supports on and off RPMh clock resources. Let's extend the driver by add support for clocks that are managed by a different type of RPMh resource known as Bus Clock Manager(BCM). The BCM is a configurable shared resource aggregator that scales performance based on a set of frequency points. The Qualcomm IP Accelerator (IPA) clock is an example of a resource that is managed by the BCM and this a requirement from the IPA driver in order to scale its core clock. > > Signed-off-by: David Dai <daidavid1@xxxxxxxxxxxxxx> > --- > drivers/clk/qcom/clk-rpmh.c | 141 ++++++++++++++++++++++++++++++++++ > include/dt-bindings/clock/qcom,rpmh.h | 1 + > 2 files changed, 142 insertions(+) > > diff --git a/drivers/clk/qcom/clk-rpmh.c b/drivers/clk/qcom/clk-rpmh.c > index 9f4fc77..ee78c4b 100644 > --- a/drivers/clk/qcom/clk-rpmh.c > +++ b/drivers/clk/qcom/clk-rpmh.c > @@ -18,6 +18,31 @@ > #define CLK_RPMH_ARC_EN_OFFSET 0 > #define CLK_RPMH_VRM_EN_OFFSET 4 > > +#define BCM_TCS_CMD_COMMIT_MASK 0x40000000 > +#define BCM_TCS_CMD_VALID_SHIFT 29 > +#define BCM_TCS_CMD_VOTE_MASK 0x3fff > +#define BCM_TCS_CMD_VOTE_SHIFT 0 > + > +#define BCM_TCS_CMD(valid, vote) \ > + (BCM_TCS_CMD_COMMIT_MASK | \ > + ((valid) << BCM_TCS_CMD_VALID_SHIFT) | \ > + ((cpu_to_le32(vote) & \ Why? > + BCM_TCS_CMD_VOTE_MASK) << BCM_TCS_CMD_VOTE_SHIFT)) > + > +/** > + * struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager(BCM) > + * @unit: divisor used to convert Hz value to an RPMh msg > + * @width: multiplier used to convert Hz value to an RPMh msg > + * @vcd: virtual clock domain that this bcm belongs to > + * @reserved: reserved to pad the struct > + */ > +struct bcm_db { > + __le32 unit; > + __le16 width; > + u8 vcd; > + u8 reserved; > +}; > + > /** > * struct clk_rpmh - individual rpmh clock data structure > * @hw: handle between common and hardware-specific interfaces > @@ -29,6 +54,7 @@ > * @aggr_state: rpmh clock aggregated state > * @last_sent_aggr_state: rpmh clock last aggr state sent to RPMh > * @valid_state_mask: mask to determine the state of the rpmh clock > + * @aux_data: data specific to the bcm rpmh resource But there isn't aux_data. Is this supposed to be unit? And what is unit going to be? 1000? > * @dev: device to which it is attached > * @peer: pointer to the clock rpmh sibling > */ > @@ -42,6 +68,7 @@ struct clk_rpmh { > u32 aggr_state; > u32 last_sent_aggr_state; > u32 valid_state_mask; > + u32 unit; > struct device *dev; > struct clk_rpmh *peer; > }; > @@ -210,6 +248,91 @@ static unsigned long clk_rpmh_recalc_rate(struct clk_hw *hw, > .recalc_rate = clk_rpmh_recalc_rate, > }; > > +static int clk_rpmh_bcm_send_cmd(struct clk_rpmh *c, bool enable) > +{ > + struct tcs_cmd cmd = { 0 }; > + u32 cmd_state; > + int ret; > + > + mutex_lock(&rpmh_clk_lock); > + > + cmd_state = enable ? (c->aggr_state ? c->aggr_state : 1) : 0; Make this into an if statement instead of double ternary? cmd_state = 0; if (enable) { cmd_state = 1; if (c->aggr_state) cmd_state = c->aggr_state; } > + > + if (c->last_sent_aggr_state == cmd_state) > + return 0; We just returned with a mutex held. Oops! > + > + cmd.addr = c->res_addr; > + cmd.data = BCM_TCS_CMD(enable, cmd_state); > + > + ret = rpmh_write_async(c->dev, RPMH_ACTIVE_ONLY_STATE, &cmd, 1); > + if (ret) { > + dev_err(c->dev, "set active state of %s failed: (%d)\n", > + c->res_name, ret); > + return ret; Again! > + } > + > + c->last_sent_aggr_state = cmd_state; > + > + mutex_unlock(&rpmh_clk_lock); > + > + return 0; > +} > + > +static int clk_rpmh_bcm_prepare(struct clk_hw *hw) > +{ > + struct clk_rpmh *c = to_clk_rpmh(hw); > + int ret; > + > + ret = clk_rpmh_bcm_send_cmd(c, true); > + > + return ret; Just write return clk_rpmh_bcm_send_cmd(...) > +}; > + > +static void clk_rpmh_bcm_unprepare(struct clk_hw *hw) > +{ > + struct clk_rpmh *c = to_clk_rpmh(hw); > + > + clk_rpmh_bcm_send_cmd(c, false); > +}; > + > +static int clk_rpmh_bcm_set_rate(struct clk_hw *hw, unsigned long rate, > + unsigned long parent_rate) > +{ > + struct clk_rpmh *c = to_clk_rpmh(hw); > + > + c->aggr_state = rate / c->unit; > + /* > + * Since any non-zero value sent to hw would result in enabling the > + * clock, only send the value if the clock has already been prepared. > + */ > + if (clk_hw_is_prepared(hw)) This is sad, but OK. > + clk_rpmh_bcm_send_cmd(c, true); > + > + return 0; > +}; > + [...] > @@ -217,6 +340,7 @@ static unsigned long clk_rpmh_recalc_rate(struct clk_hw *hw, > DEFINE_CLK_RPMH_VRM(sdm845, rf_clk1, rf_clk1_ao, "rfclka1", 1); > DEFINE_CLK_RPMH_VRM(sdm845, rf_clk2, rf_clk2_ao, "rfclka2", 1); > DEFINE_CLK_RPMH_VRM(sdm845, rf_clk3, rf_clk3_ao, "rfclka3", 1); > +DEFINE_CLK_RPMH_BCM(sdm845, ipa, "IP0"); It's really IP0?! What was wrong with IPA? > > static struct clk_hw *sdm845_rpmh_clocks[] = { > [RPMH_CXO_CLK] = &sdm845_bi_tcxo.hw, > @@ -275,6 +402,20 @@ static int clk_rpmh_probe(struct platform_device *pdev) > rpmh_clk->res_name); > return -ENODEV; > } > + > + data = cmd_db_read_aux_data(rpmh_clk->res_name, &aux_data_len); > + if (IS_ERR(data)) { > + ret = PTR_ERR(data); > + dev_err(&pdev->dev, > + "error reading RPMh aux data for %s (%d)\n", > + rpmh_clk->res_name, ret); > + return ret; Weird indent here.