Re: [PATCH v3] phy: qualcomm: eusb2-repeater: Rework init to drop redundant zero-out loop

From: Elliot Berman
Date: Wed Jan 31 2024 - 21:19:36 EST


On Mon, Jan 29, 2024 at 03:03:24PM +0200, Abel Vesa wrote:
> The device match config init table already has zero values, so rework
> the container struct to hold a copy of the init table that can be
> override be the DT specified values. By doing this, only the number of
> vregs remain in the device match config that will be later needed, so
> instead of holding the cfg after probe, store the number of vregs in the
> container struct.
>
> Fixes: 99a517a582fc ("phy: qualcomm: phy-qcom-eusb2-repeater: Zero out untouched tuning regs")
> Signed-off-by: Abel Vesa <abel.vesa@xxxxxxxxxx>

I forgot I've been having this on my device for past few days and USB's
been coming up consistently, so I'll count that as:

Tested-by: Elliot Berman <quic_eberman@xxxxxxxxxxx> # sm8650-qrd

> ---
> Changes in v3:
> - Reworked so that it uses base + reg-index.
> - Link to v2: https://lore.kernel.org/r/20240105-phy-qcom-eusb2-repeater-fixes-v2-0-775d98e7df05@xxxxxxxxxx
>
> Changes in v2:
> - The regfields is being dropped from the repeater init, but it's done
> in the second patch in order to not break bisectability, as it is
> still needed by the zero-out loop.
> - Added Konrad's R-b tag to the first patch. Did not add Elliot's T-b
> tag as the second patch has been reworked massively.
> - The zero-out loop is dropped now by holding a copy of the init_tlb in
> the container struct. This led to dropping the cfg from the container
> struct (see second patch commit message for more details).
> - Link to v1: https://lore.kernel.org/r/20240104-phy-qcom-eusb2-repeater-fixes-v1-0-047b7b6b8333@xxxxxxxxxx
> ---
> drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c | 166 +++++++++----------------
> 1 file changed, 62 insertions(+), 104 deletions(-)
>
> diff --git a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
> index a623f092b11f..a43e20abb10d 100644
> --- a/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
> +++ b/drivers/phy/qualcomm/phy-qcom-eusb2-repeater.c
> @@ -37,56 +37,28 @@
> #define EUSB2_TUNE_EUSB_EQU 0x5A
> #define EUSB2_TUNE_EUSB_HS_COMP_CUR 0x5B
>
> -#define QCOM_EUSB2_REPEATER_INIT_CFG(r, v) \
> - { \
> - .reg = r, \
> - .val = v, \
> - }
> -
> -enum reg_fields {
> - F_TUNE_EUSB_HS_COMP_CUR,
> - F_TUNE_EUSB_EQU,
> - F_TUNE_EUSB_SLEW,
> - F_TUNE_USB2_HS_COMP_CUR,
> - F_TUNE_USB2_PREEM,
> - F_TUNE_USB2_EQU,
> - F_TUNE_USB2_SLEW,
> - F_TUNE_SQUELCH_U,
> - F_TUNE_HSDISC,
> - F_TUNE_RES_FSDIF,
> - F_TUNE_IUSB2,
> - F_TUNE_USB2_CROSSOVER,
> - F_NUM_TUNE_FIELDS,
> -
> - F_FORCE_VAL_5 = F_NUM_TUNE_FIELDS,
> - F_FORCE_EN_5,
> -
> - F_EN_CTL1,
> -
> - F_RPTR_STATUS,
> - F_NUM_FIELDS,
> -};
> -
> -static struct reg_field eusb2_repeater_tune_reg_fields[F_NUM_FIELDS] = {
> - [F_TUNE_EUSB_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_EUSB_HS_COMP_CUR, 0, 1),
> - [F_TUNE_EUSB_EQU] = REG_FIELD(EUSB2_TUNE_EUSB_EQU, 0, 1),
> - [F_TUNE_EUSB_SLEW] = REG_FIELD(EUSB2_TUNE_EUSB_SLEW, 0, 1),
> - [F_TUNE_USB2_HS_COMP_CUR] = REG_FIELD(EUSB2_TUNE_USB2_HS_COMP_CUR, 0, 1),
> - [F_TUNE_USB2_PREEM] = REG_FIELD(EUSB2_TUNE_USB2_PREEM, 0, 2),
> - [F_TUNE_USB2_EQU] = REG_FIELD(EUSB2_TUNE_USB2_EQU, 0, 1),
> - [F_TUNE_USB2_SLEW] = REG_FIELD(EUSB2_TUNE_USB2_SLEW, 0, 1),
> - [F_TUNE_SQUELCH_U] = REG_FIELD(EUSB2_TUNE_SQUELCH_U, 0, 2),
> - [F_TUNE_HSDISC] = REG_FIELD(EUSB2_TUNE_HSDISC, 0, 2),
> - [F_TUNE_RES_FSDIF] = REG_FIELD(EUSB2_TUNE_RES_FSDIF, 0, 2),
> - [F_TUNE_IUSB2] = REG_FIELD(EUSB2_TUNE_IUSB2, 0, 3),
> - [F_TUNE_USB2_CROSSOVER] = REG_FIELD(EUSB2_TUNE_USB2_CROSSOVER, 0, 2),
> -
> - [F_FORCE_VAL_5] = REG_FIELD(EUSB2_FORCE_VAL_5, 0, 7),
> - [F_FORCE_EN_5] = REG_FIELD(EUSB2_FORCE_EN_5, 0, 7),
> -
> - [F_EN_CTL1] = REG_FIELD(EUSB2_EN_CTL1, 0, 7),
> -
> - [F_RPTR_STATUS] = REG_FIELD(EUSB2_RPTR_STATUS, 0, 7),
> +enum eusb2_reg_layout {
> + TUNE_EUSB_HS_COMP_CUR,
> + TUNE_EUSB_EQU,
> + TUNE_EUSB_SLEW,
> + TUNE_USB2_HS_COMP_CUR,
> + TUNE_USB2_PREEM,
> + TUNE_USB2_EQU,
> + TUNE_USB2_SLEW,
> + TUNE_SQUELCH_U,
> + TUNE_HSDISC,
> + TUNE_RES_FSDIF,
> + TUNE_IUSB2,
> + TUNE_USB2_CROSSOVER,
> + NUM_TUNE_FIELDS,
> +
> + FORCE_VAL_5 = NUM_TUNE_FIELDS,
> + FORCE_EN_5,
> +
> + EN_CTL1,
> +
> + RPTR_STATUS,
> + LAYOUT_SIZE,
> };
>
> struct eusb2_repeater_cfg {
> @@ -98,10 +70,11 @@ struct eusb2_repeater_cfg {
>
> struct eusb2_repeater {
> struct device *dev;
> - struct regmap_field *regs[F_NUM_FIELDS];
> + struct regmap *regmap;
> struct phy *phy;
> struct regulator_bulk_data *vregs;
> const struct eusb2_repeater_cfg *cfg;
> + u32 base;
> enum phy_mode mode;
> };
>
> @@ -109,10 +82,10 @@ static const char * const pm8550b_vreg_l[] = {
> "vdd18", "vdd3",
> };
>
> -static const u32 pm8550b_init_tbl[F_NUM_TUNE_FIELDS] = {
> - [F_TUNE_IUSB2] = 0x8,
> - [F_TUNE_SQUELCH_U] = 0x3,
> - [F_TUNE_USB2_PREEM] = 0x5,
> +static const u32 pm8550b_init_tbl[NUM_TUNE_FIELDS] = {
> + [TUNE_IUSB2] = 0x8,
> + [TUNE_SQUELCH_U] = 0x3,
> + [TUNE_USB2_PREEM] = 0x5,
> };
>
> static const struct eusb2_repeater_cfg pm8550b_eusb2_cfg = {
> @@ -140,47 +113,42 @@ static int eusb2_repeater_init_vregs(struct eusb2_repeater *rptr)
>
> static int eusb2_repeater_init(struct phy *phy)
> {
> - struct reg_field *regfields = eusb2_repeater_tune_reg_fields;
> struct eusb2_repeater *rptr = phy_get_drvdata(phy);
> struct device_node *np = rptr->dev->of_node;
> - u32 init_tbl[F_NUM_TUNE_FIELDS] = { 0 };
> - u8 override;
> + struct regmap *regmap = rptr->regmap;
> + const u32 *init_tbl = rptr->cfg->init_tbl;
> + u8 tune_usb2_preem = init_tbl[TUNE_USB2_PREEM];
> + u8 tune_hsdisc = init_tbl[TUNE_HSDISC];
> + u8 tune_iusb2 = init_tbl[TUNE_IUSB2];
> + u32 base = rptr->base;
> u32 val;
> int ret;
> - int i;
> +
> + of_property_read_u8(np, "qcom,tune-usb2-amplitude", &tune_iusb2);
> + of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &tune_hsdisc);
> + of_property_read_u8(np, "qcom,tune-usb2-preem", &tune_usb2_preem);
>
> ret = regulator_bulk_enable(rptr->cfg->num_vregs, rptr->vregs);
> if (ret)
> return ret;
>
> - regmap_field_update_bits(rptr->regs[F_EN_CTL1], EUSB2_RPTR_EN, EUSB2_RPTR_EN);
> + regmap_write(regmap, base + EUSB2_EN_CTL1, EUSB2_RPTR_EN);
>
> - for (i = 0; i < F_NUM_TUNE_FIELDS; i++) {
> - if (init_tbl[i]) {
> - regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]);
> - } else {
> - /* Write 0 if there's no value set */
> - u32 mask = GENMASK(regfields[i].msb, regfields[i].lsb);
> -
> - regmap_field_update_bits(rptr->regs[i], mask, 0);
> - }
> - }
> - memcpy(init_tbl, rptr->cfg->init_tbl, sizeof(init_tbl));
> + regmap_write(regmap, base + EUSB2_TUNE_EUSB_HS_COMP_CUR, init_tbl[TUNE_EUSB_HS_COMP_CUR]);
> + regmap_write(regmap, base + EUSB2_TUNE_EUSB_EQU, init_tbl[TUNE_EUSB_EQU]);
> + regmap_write(regmap, base + EUSB2_TUNE_EUSB_SLEW, init_tbl[TUNE_EUSB_SLEW]);
> + regmap_write(regmap, base + EUSB2_TUNE_USB2_HS_COMP_CUR, init_tbl[TUNE_USB2_HS_COMP_CUR]);
> + regmap_write(regmap, base + EUSB2_TUNE_USB2_EQU, init_tbl[TUNE_USB2_EQU]);
> + regmap_write(regmap, base + EUSB2_TUNE_USB2_SLEW, init_tbl[TUNE_USB2_SLEW]);
> + regmap_write(regmap, base + EUSB2_TUNE_SQUELCH_U, init_tbl[TUNE_SQUELCH_U]);
> + regmap_write(regmap, base + EUSB2_TUNE_RES_FSDIF, init_tbl[TUNE_RES_FSDIF]);
> + regmap_write(regmap, base + EUSB2_TUNE_USB2_CROSSOVER, init_tbl[TUNE_USB2_CROSSOVER]);
>
> - if (!of_property_read_u8(np, "qcom,tune-usb2-amplitude", &override))
> - init_tbl[F_TUNE_IUSB2] = override;
> + regmap_write(regmap, base + EUSB2_TUNE_USB2_PREEM, tune_usb2_preem);
> + regmap_write(regmap, base + EUSB2_TUNE_HSDISC, tune_hsdisc);
> + regmap_write(regmap, base + EUSB2_TUNE_IUSB2, tune_iusb2);
>
> - if (!of_property_read_u8(np, "qcom,tune-usb2-disc-thres", &override))
> - init_tbl[F_TUNE_HSDISC] = override;
> -
> - if (!of_property_read_u8(np, "qcom,tune-usb2-preem", &override))
> - init_tbl[F_TUNE_USB2_PREEM] = override;
> -
> - for (i = 0; i < F_NUM_TUNE_FIELDS; i++)
> - regmap_field_update_bits(rptr->regs[i], init_tbl[i], init_tbl[i]);
> -
> - ret = regmap_field_read_poll_timeout(rptr->regs[F_RPTR_STATUS],
> - val, val & RPTR_OK, 10, 5);
> + ret = regmap_read_poll_timeout(regmap, base + EUSB2_RPTR_STATUS, val, val & RPTR_OK, 10, 5);
> if (ret)
> dev_err(rptr->dev, "initialization timed-out\n");
>
> @@ -191,6 +159,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
> enum phy_mode mode, int submode)
> {
> struct eusb2_repeater *rptr = phy_get_drvdata(phy);
> + struct regmap *regmap = rptr->regmap;
> + u32 base = rptr->base;
>
> switch (mode) {
> case PHY_MODE_USB_HOST:
> @@ -199,10 +169,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
> * per eUSB 1.2 Spec. Below implement software workaround until
> * PHY and controller is fixing seen observation.
> */
> - regmap_field_update_bits(rptr->regs[F_FORCE_EN_5],
> - F_CLK_19P2M_EN, F_CLK_19P2M_EN);
> - regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5],
> - V_CLK_19P2M_EN, V_CLK_19P2M_EN);
> + regmap_write(regmap, base + EUSB2_FORCE_EN_5, F_CLK_19P2M_EN);
> + regmap_write(regmap, base + EUSB2_FORCE_VAL_5, V_CLK_19P2M_EN);
> break;
> case PHY_MODE_USB_DEVICE:
> /*
> @@ -211,10 +179,8 @@ static int eusb2_repeater_set_mode(struct phy *phy,
> * repeater doesn't clear previous value due to shared
> * regulators (say host <-> device mode switch).
> */
> - regmap_field_update_bits(rptr->regs[F_FORCE_EN_5],
> - F_CLK_19P2M_EN, 0);
> - regmap_field_update_bits(rptr->regs[F_FORCE_VAL_5],
> - V_CLK_19P2M_EN, 0);
> + regmap_write(regmap, base + EUSB2_FORCE_EN_5, 0);
> + regmap_write(regmap, base + EUSB2_FORCE_VAL_5, 0);
> break;
> default:
> return -EINVAL;
> @@ -243,9 +209,8 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
> struct device *dev = &pdev->dev;
> struct phy_provider *phy_provider;
> struct device_node *np = dev->of_node;
> - struct regmap *regmap;
> - int i, ret;
> u32 res;
> + int ret;
>
> rptr = devm_kzalloc(dev, sizeof(*rptr), GFP_KERNEL);
> if (!rptr)
> @@ -258,22 +223,15 @@ static int eusb2_repeater_probe(struct platform_device *pdev)
> if (!rptr->cfg)
> return -EINVAL;
>
> - regmap = dev_get_regmap(dev->parent, NULL);
> - if (!regmap)
> + rptr->regmap = dev_get_regmap(dev->parent, NULL);
> + if (!rptr->regmap)
> return -ENODEV;
>
> ret = of_property_read_u32(np, "reg", &res);
> if (ret < 0)
> return ret;
>
> - for (i = 0; i < F_NUM_FIELDS; i++)
> - eusb2_repeater_tune_reg_fields[i].reg += res;
> -
> - ret = devm_regmap_field_bulk_alloc(dev, regmap, rptr->regs,
> - eusb2_repeater_tune_reg_fields,
> - F_NUM_FIELDS);
> - if (ret)
> - return ret;
> + rptr->base = res;
>
> ret = eusb2_repeater_init_vregs(rptr);
> if (ret < 0) {
>
> ---
> base-commit: 01af33cc9894b4489fb68fa35c40e9fe85df63dc
> change-id: 20240104-phy-qcom-eusb2-repeater-fixes-c9201113032c
>
> Best regards,
> --
> Abel Vesa <abel.vesa@xxxxxxxxxx>
>