lkml.org 
[lkml]   [2020]   [Jun]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH V8 1/8] soc: qcom: geni: Support for ICC voting
    Date
    Add necessary macros and structure variables to support ICC BW
    voting from individual SE drivers.

    Signed-off-by: Akash Asthana <akashast@codeaurora.org>
    Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
    ---
    Changes in V2:
    - As per Bjorn's comment dropped enums for ICC paths, given the three
    paths individual members

    Changes in V3:
    - Add geni_icc_get, geni_icc_vote_on and geni_icc_vote_off as helper API.
    - Add geni_icc_path structure in common header

    Changes in V4:
    - As per Bjorn's comment print error message in geni_icc_get if return
    value is not -EPROBE_DEFER.
    - As per Bjorn's comment remove NULL on path before calling icc_set_bw
    API.
    - As per Bjorn's comment drop __func__ print.
    - As per Matthias's comment, make ICC path a array instead of individual
    member entry in geni_se struct.

    Changes in V5:
    - As per Matthias's comment defined enums for ICC paths.
    - Integrate icc_enable/disable with power on/off call for driver.
    - As per Matthias's comment added icc_path_names array to print icc path name
    in failure case.
    - As per Georgi's suggestion assume peak_bw = avg_bw if not mentioned.

    Changes in V6:
    - Addressed nitpicks from Matthias.

    Changes in V7:
    - As per Matthias's comment removed usage of peak_bw variable because we don't
    have explicit peak requirement, we were voting peak = avg and this can be
    tracked using single variable for avg bw.
    - As per Matthias's comment improved print log.

    Changes in V8:
    - No change.

    Note: I have ignored below check patch suggestion because it was throwing
    compilation error as 'icc_ddr' is not compile time comstant.

    WARNING: char * array declaration might be better as static const
    - FILE: drivers/soc/qcom/qcom-geni-se.c:726:
    - const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};

    drivers/soc/qcom/qcom-geni-se.c | 82 +++++++++++++++++++++++++++++++++++++++++
    include/linux/qcom-geni-se.h | 38 +++++++++++++++++++
    2 files changed, 120 insertions(+)

    diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
    index 7d622ea..950e347 100644
    --- a/drivers/soc/qcom/qcom-geni-se.c
    +++ b/drivers/soc/qcom/qcom-geni-se.c
    @@ -92,6 +92,9 @@ struct geni_wrapper {
    struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
    };

    +static const char * const icc_path_names[] = {"qup-core", "qup-config",
    + "qup-memory"};
    +
    #define QUP_HW_VER_REG 0x4

    /* Common SE registers */
    @@ -720,6 +723,85 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
    }
    EXPORT_SYMBOL(geni_se_rx_dma_unprep);

    +int geni_icc_get(struct geni_se *se, const char *icc_ddr)
    +{
    + int i, err;
    + const char *icc_names[] = {"qup-core", "qup-config", icc_ddr};
    +
    + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
    + if (!icc_names[i])
    + continue;
    +
    + se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]);
    + if (IS_ERR(se->icc_paths[i].path))
    + goto err;
    + }
    +
    + return 0;
    +
    +err:
    + err = PTR_ERR(se->icc_paths[i].path);
    + if (err != -EPROBE_DEFER)
    + dev_err_ratelimited(se->dev, "Failed to get ICC path '%s': %d\n",
    + icc_names[i], err);
    + return err;
    +
    +}
    +EXPORT_SYMBOL(geni_icc_get);
    +
    +int geni_icc_set_bw(struct geni_se *se)
    +{
    + int i, ret;
    +
    + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
    + ret = icc_set_bw(se->icc_paths[i].path,
    + se->icc_paths[i].avg_bw, se->icc_paths[i].avg_bw);
    + if (ret) {
    + dev_err_ratelimited(se->dev, "ICC BW voting failed on path '%s': %d\n",
    + icc_path_names[i], ret);
    + return ret;
    + }
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL(geni_icc_set_bw);
    +
    +/* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */
    +int geni_icc_enable(struct geni_se *se)
    +{
    + int i, ret;
    +
    + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
    + ret = icc_enable(se->icc_paths[i].path);
    + if (ret) {
    + dev_err_ratelimited(se->dev, "ICC enable failed on path '%s': %d\n",
    + icc_path_names[i], ret);
    + return ret;
    + }
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL(geni_icc_enable);
    +
    +int geni_icc_disable(struct geni_se *se)
    +{
    + int i, ret;
    +
    + for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) {
    + ret = icc_disable(se->icc_paths[i].path);
    + if (ret) {
    + dev_err_ratelimited(se->dev, "ICC disable failed on path '%s': %d\n",
    + icc_path_names[i], ret);
    + return ret;
    + }
    + }
    +
    + return 0;
    +}
    +EXPORT_SYMBOL(geni_icc_disable);
    +
    static int geni_se_probe(struct platform_device *pdev)
    {
    struct device *dev = &pdev->dev;
    diff --git a/include/linux/qcom-geni-se.h b/include/linux/qcom-geni-se.h
    index dd46494..80dbc01 100644
    --- a/include/linux/qcom-geni-se.h
    +++ b/include/linux/qcom-geni-se.h
    @@ -6,6 +6,8 @@
    #ifndef _LINUX_QCOM_GENI_SE
    #define _LINUX_QCOM_GENI_SE

    +#include <linux/interconnect.h>
    +
    /* Transfer mode supported by GENI Serial Engines */
    enum geni_se_xfer_mode {
    GENI_SE_INVALID,
    @@ -25,6 +27,17 @@ enum geni_se_protocol_type {
    struct geni_wrapper;
    struct clk;

    +enum geni_icc_path_index {
    + GENI_TO_CORE,
    + CPU_TO_GENI,
    + GENI_TO_DDR
    +};
    +
    +struct geni_icc_path {
    + struct icc_path *path;
    + unsigned int avg_bw;
    +};
    +
    /**
    * struct geni_se - GENI Serial Engine
    * @base: Base Address of the Serial Engine's register block
    @@ -33,6 +46,7 @@ struct clk;
    * @clk: Handle to the core serial engine clock
    * @num_clk_levels: Number of valid clock levels in clk_perf_tbl
    * @clk_perf_tbl: Table of clock frequency input to serial engine clock
    + * @icc_paths: Array of ICC paths for SE
    */
    struct geni_se {
    void __iomem *base;
    @@ -41,6 +55,7 @@ struct geni_se {
    struct clk *clk;
    unsigned int num_clk_levels;
    unsigned long *clk_perf_tbl;
    + struct geni_icc_path icc_paths[3];
    };

    /* Common SE registers */
    @@ -229,6 +244,21 @@ struct geni_se {
    #define GENI_SE_VERSION_MINOR(ver) ((ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT)
    #define GENI_SE_VERSION_STEP(ver) (ver & HW_VER_STEP_MASK)

    +/*
    + * Define bandwidth thresholds that cause the underlying Core 2X interconnect
    + * clock to run at the named frequency. These baseline values are recommended
    + * by the hardware team, and are not dynamically scaled with GENI bandwidth
    + * beyond basic on/off.
    + */
    +#define CORE_2X_19_2_MHZ 960
    +#define CORE_2X_50_MHZ 2500
    +#define CORE_2X_100_MHZ 5000
    +#define CORE_2X_150_MHZ 7500
    +#define CORE_2X_200_MHZ 10000
    +#define CORE_2X_236_MHZ 16383
    +
    +#define GENI_DEFAULT_BW Bps_to_icc(1000)
    +
    #if IS_ENABLED(CONFIG_QCOM_GENI_SE)

    u32 geni_se_get_qup_hw_version(struct geni_se *se);
    @@ -416,5 +446,13 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
    void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);

    void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);
    +
    +int geni_icc_get(struct geni_se *se, const char *icc_ddr);
    +
    +int geni_icc_set_bw(struct geni_se *se);
    +
    +int geni_icc_enable(struct geni_se *se);
    +
    +int geni_icc_disable(struct geni_se *se);
    #endif
    #endif
    --
    The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,\na Linux Foundation Collaborative Project
    \
     
     \ /
      Last update: 2020-06-23 12:40    [W:3.723 / U:0.376 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site