[PATCH v1 0/8] Support USB for Meson A1

Hello!
This patchset adds USB stack support for Amlogic A1 SoC's series. Made reset / phy / dwc3 drivers more flexible and added support for A1 board.
Alexey Romanov (7): dt-bindings: reset: add Meson A1 reset bindings reset: add support for Amlogic A1 family phy: get rid of raw hex values phy: move clk enable/disable in init/exit phy: support Amlogic A1 family dwc3: add support for Amlogic A1 family arch: a1: introduce USB initialization functionality
Igor Prusov (1): a1: clk: Add missing CLKID_USB_PHY_IN gate
arch/arm/mach-meson/board-a1.c | 89 +++++++ drivers/clk/meson/a1.c | 3 + drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 233 ++++++++++++++++-- drivers/reset/reset-meson.c | 42 +++- drivers/usb/dwc3/dwc3-meson-g12a.c | 73 +++++- .../reset/amlogic,meson-a1-reset.h | 76 ++++++ 7 files changed, 484 insertions(+), 34 deletions(-) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h

Get this from Linux 6.6-rc3.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- .../reset/amlogic,meson-a1-reset.h | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h
diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h new file mode 100644 index 0000000000..2c749c655e --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-a1-reset.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) 2019 Amlogic, Inc. All rights reserved. + * Author: Xingyu Chen xingyu.chen@amlogic.com + * + * Copyright (c) 2023, SberDevices, Inc. + * Author: Alexey Romanov avromanov@salutedevices.com + */ + +#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H +#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H + +/* RESET0 */ +/* 0 */ +#define RESET_AM2AXI_VAD 1 +/* 2-3 */ +#define RESET_PSRAM 4 +#define RESET_PAD_CTRL 5 +/* 6 */ +#define RESET_TEMP_SENSOR 7 +#define RESET_AM2AXI_DEV 8 +/* 9 */ +#define RESET_SPICC_A 10 +#define RESET_MSR_CLK 11 +#define RESET_AUDIO 12 +#define RESET_ANALOG_CTRL 13 +#define RESET_SAR_ADC 14 +#define RESET_AUDIO_VAD 15 +#define RESET_CEC 16 +#define RESET_PWM_EF 17 +#define RESET_PWM_CD 18 +#define RESET_PWM_AB 19 +/* 20 */ +#define RESET_IR_CTRL 21 +#define RESET_I2C_S_A 22 +/* 23 */ +#define RESET_I2C_M_D 24 +#define RESET_I2C_M_C 25 +#define RESET_I2C_M_B 26 +#define RESET_I2C_M_A 27 +#define RESET_I2C_PROD_AHB 28 +#define RESET_I2C_PROD 29 +/* 30-31 */ + +/* RESET1 */ +#define RESET_ACODEC 32 +#define RESET_DMA 33 +#define RESET_SD_EMMC_A 34 +/* 35 */ +#define RESET_USBCTRL 36 +/* 37 */ +#define RESET_USBPHY 38 +/* 39-41 */ +#define RESET_RSA 42 +#define RESET_DMC 43 +/* 44 */ +#define RESET_IRQ_CTRL 45 +/* 46 */ +#define RESET_NIC_VAD 47 +#define RESET_NIC_AXI 48 +#define RESET_RAMA 49 +#define RESET_RAMB 50 +/* 51-52 */ +#define RESET_ROM 53 +#define RESET_SPIFC 54 +#define RESET_GIC 55 +#define RESET_UART_C 56 +#define RESET_UART_B 57 +#define RESET_UART_A 58 +#define RESET_OSC_RING 59 +/* 60-63 */ + +/* RESET2 */ +/* 64-95 */ + +#endif

On 02/10/2023 18:58, Alexey Romanov wrote:
Get this from Linux 6.6-rc3.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
.../reset/amlogic,meson-a1-reset.h | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 include/dt-bindings/reset/amlogic,meson-a1-reset.h
diff --git a/include/dt-bindings/reset/amlogic,meson-a1-reset.h b/include/dt-bindings/reset/amlogic,meson-a1-reset.h new file mode 100644 index 0000000000..2c749c655e --- /dev/null +++ b/include/dt-bindings/reset/amlogic,meson-a1-reset.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (c) 2019 Amlogic, Inc. All rights reserved.
- Author: Xingyu Chen xingyu.chen@amlogic.com
- Copyright (c) 2023, SberDevices, Inc.
- Author: Alexey Romanov avromanov@salutedevices.com
- */
+#ifndef _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H +#define _DT_BINDINGS_AMLOGIC_MESON_A1_RESET_H
+/* RESET0 */ +/* 0 */ +#define RESET_AM2AXI_VAD 1 +/* 2-3 */ +#define RESET_PSRAM 4 +#define RESET_PAD_CTRL 5 +/* 6 */ +#define RESET_TEMP_SENSOR 7 +#define RESET_AM2AXI_DEV 8 +/* 9 */ +#define RESET_SPICC_A 10 +#define RESET_MSR_CLK 11 +#define RESET_AUDIO 12 +#define RESET_ANALOG_CTRL 13 +#define RESET_SAR_ADC 14 +#define RESET_AUDIO_VAD 15 +#define RESET_CEC 16 +#define RESET_PWM_EF 17 +#define RESET_PWM_CD 18 +#define RESET_PWM_AB 19 +/* 20 */ +#define RESET_IR_CTRL 21 +#define RESET_I2C_S_A 22 +/* 23 */ +#define RESET_I2C_M_D 24 +#define RESET_I2C_M_C 25 +#define RESET_I2C_M_B 26 +#define RESET_I2C_M_A 27 +#define RESET_I2C_PROD_AHB 28 +#define RESET_I2C_PROD 29 +/* 30-31 */
+/* RESET1 */ +#define RESET_ACODEC 32 +#define RESET_DMA 33 +#define RESET_SD_EMMC_A 34 +/* 35 */ +#define RESET_USBCTRL 36 +/* 37 */ +#define RESET_USBPHY 38 +/* 39-41 */ +#define RESET_RSA 42 +#define RESET_DMC 43 +/* 44 */ +#define RESET_IRQ_CTRL 45 +/* 46 */ +#define RESET_NIC_VAD 47 +#define RESET_NIC_AXI 48 +#define RESET_RAMA 49 +#define RESET_RAMB 50 +/* 51-52 */ +#define RESET_ROM 53 +#define RESET_SPIFC 54 +#define RESET_GIC 55 +#define RESET_UART_C 56 +#define RESET_UART_B 57 +#define RESET_UART_A 58 +#define RESET_OSC_RING 59 +/* 60-63 */
+/* RESET2 */ +/* 64-95 */
+#endif
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/reset/reset-meson.c | 42 +++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 64bc696f13..9d0c8b354f 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -13,18 +13,26 @@ #include <reset-uclass.h> #include <regmap.h> #include <linux/bitops.h> +#include <linux/delay.h>
-#define REG_COUNT 8 #define BITS_PER_REG 32 -#define LEVEL_OFFSET 0x7c + +struct meson_reset_drvdata { + unsigned int reg_count; + unsigned int level_offset; +};
struct meson_reset_priv { struct regmap *regmap; + struct meson_reset_drvdata *drvdata; };
static int meson_reset_request(struct reset_ctl *reset_ctl) { - if (reset_ctl->id > (REG_COUNT * BITS_PER_REG)) + struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; + + if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) return -EINVAL;
return 0; @@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl) static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) { struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev); + struct meson_reset_drvdata *data = priv->drvdata; uint bank = reset_ctl->id / BITS_PER_REG; uint offset = reset_ctl->id % BITS_PER_REG; - uint reg_offset = LEVEL_OFFSET + (bank << 2); + uint reg_offset = data->level_offset + (bank << 2); uint val;
regmap_read(priv->regmap, reg_offset, &val); @@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, };
+static const struct meson_reset_drvdata meson_gxbb_data = { + .reg_count = 8, + .level_offset = 0x7c, +}; + +static const struct meson_reset_drvdata meson_a1_data = { + .reg_count = 3, + .level_offset = 0x40, +}; + static const struct udevice_id meson_reset_ids[] = { - { .compatible = "amlogic,meson-gxbb-reset" }, - { .compatible = "amlogic,meson-axg-reset" }, + { + .compatible = "amlogic,meson-gxbb-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-axg-reset", + .data = (ulong)&meson_gxbb_data, + }, + { + .compatible = "amlogic,meson-a1-reset", + .data = (ulong)&meson_a1_data, + }, { } };
static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev); + priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev);
return regmap_init_mem(dev_ofnode(dev), &priv->regmap); }

On 02/10/2023 18:58, Alexey Romanov wrote:
This patch adds reset support for the Amlogic A1 family. We add the structure meson_reset_drvdata, which in the future will allow this driver to be used for other families by declaring only the correct parameters reg_count and level_offset.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/reset/reset-meson.c | 42 +++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-)
diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 64bc696f13..9d0c8b354f 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -13,18 +13,26 @@ #include <reset-uclass.h> #include <regmap.h> #include <linux/bitops.h> +#include <linux/delay.h>
-#define REG_COUNT 8 #define BITS_PER_REG 32 -#define LEVEL_OFFSET 0x7c
+struct meson_reset_drvdata {
- unsigned int reg_count;
- unsigned int level_offset;
+};
struct meson_reset_priv { struct regmap *regmap;
struct meson_reset_drvdata *drvdata; };
static int meson_reset_request(struct reset_ctl *reset_ctl) {
- if (reset_ctl->id > (REG_COUNT * BITS_PER_REG))
struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
struct meson_reset_drvdata *data = priv->drvdata;
if (reset_ctl->id > (data->reg_count * BITS_PER_REG)) return -EINVAL;
return 0;
@@ -33,9 +41,10 @@ static int meson_reset_request(struct reset_ctl *reset_ctl) static int meson_reset_level(struct reset_ctl *reset_ctl, bool assert) { struct meson_reset_priv *priv = dev_get_priv(reset_ctl->dev);
- struct meson_reset_drvdata *data = priv->drvdata; uint bank = reset_ctl->id / BITS_PER_REG; uint offset = reset_ctl->id % BITS_PER_REG;
- uint reg_offset = LEVEL_OFFSET + (bank << 2);
uint reg_offset = data->level_offset + (bank << 2); uint val;
regmap_read(priv->regmap, reg_offset, &val);
@@ -64,15 +73,36 @@ struct reset_ops meson_reset_ops = { .rst_deassert = meson_reset_deassert, };
+static const struct meson_reset_drvdata meson_gxbb_data = {
- .reg_count = 8,
- .level_offset = 0x7c,
+};
+static const struct meson_reset_drvdata meson_a1_data = {
- .reg_count = 3,
- .level_offset = 0x40,
+};
- static const struct udevice_id meson_reset_ids[] = {
- { .compatible = "amlogic,meson-gxbb-reset" },
- { .compatible = "amlogic,meson-axg-reset" },
{
.compatible = "amlogic,meson-gxbb-reset",
.data = (ulong)&meson_gxbb_data,
},
{
.compatible = "amlogic,meson-axg-reset",
.data = (ulong)&meson_gxbb_data,
},
{
.compatible = "amlogic,meson-a1-reset",
.data = (ulong)&meson_a1_data,
}, { } };
static int meson_reset_probe(struct udevice *dev) { struct meson_reset_priv *priv = dev_get_priv(dev);
priv->drvdata = (struct meson_reset_drvdata *)dev_get_driver_data(dev);
return regmap_init_mem(dev_ofnode(dev), &priv->regmap); }
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

It is better to use defines instead of write raw hex values in regmap.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/phy/meson-g12a-usb2.c | 161 ++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-)
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 650b88bd18..2e366b16ae 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -23,12 +23,28 @@
#include <linux/bitops.h> #include <linux/compat.h> +#include <linux/bitfield.h>
#define PHY_CTRL_R0 0x0 #define PHY_CTRL_R1 0x4 #define PHY_CTRL_R2 0x8 + #define PHY_CTRL_R3 0xc + #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) + #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) + #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) + #define PHY_CTRL_R4 0x10 + #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) + #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) + #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16) + #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24) + #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) + #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) + #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) + #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) + #define PHY_CTRL_R5 0x14 #define PHY_CTRL_R6 0x18 #define PHY_CTRL_R7 0x1c @@ -37,15 +53,93 @@ #define PHY_CTRL_R10 0x28 #define PHY_CTRL_R11 0x2c #define PHY_CTRL_R12 0x30 + #define PHY_CTRL_R13 0x34 + #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) + #define PHY_CTRL_R13_LOAD_STAT BIT(14) + #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) + #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) + #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) + #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) + #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24) + #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25) + #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26) + #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27) + #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28) + #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) + #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) + #define PHY_CTRL_R14 0x38 #define PHY_CTRL_R15 0x3c + #define PHY_CTRL_R16 0x40 + #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) + #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) + #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) + #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21) + #define PHY_CTRL_R16_MPLL_LOAD BIT(22) + #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23) + #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) + #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26) + #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) + #define PHY_CTRL_R16_MPLL_EN BIT(28) + #define PHY_CTRL_R16_MPLL_RESET BIT(29) + #define PHY_CTRL_R16_MPLL_LOCK BIT(30) + #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) + #define PHY_CTRL_R17 0x44 + #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) + #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16) + #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) + #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) + #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) + #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24) + #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28) + #define PHY_CTRL_R18 0x48 + #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0) + #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2) + #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6) + #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12) + #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13) + #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14) + #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16) + #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19) + #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22) + #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24) + #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26) + #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29) + #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31) + #define PHY_CTRL_R19 0x4c + #define PHY_CTRL_R20 0x50 + #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0) + #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1) + #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4) + #define PHY_CTRL_R20_USB2_AMON_EN BIT(5) + #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6) + #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7) + #define PHY_CTRL_R20_USB2_DMON_EN BIT(8) + #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9) + #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13) + #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14) + #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16) + #define PHY_CTRL_R20_USB2_BGR_START BIT(21) + #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24) + #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29) + #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31) + #define PHY_CTRL_R21 0x54 + #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0) + #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1) + #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2) + #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3) + #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4) + #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6) + #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20) + #define PHY_CTRL_R22 0x58 #define PHY_CTRL_R23 0x5c
@@ -78,25 +172,76 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
/* PLL Setup : 24MHz * 20 / 1 = 480MHz */ - regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414); - regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000); - regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5); + regmap_write(priv->regmap, PHY_CTRL_R16, + FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | + FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | + PHY_CTRL_R16_MPLL_LOAD | + FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | + PHY_CTRL_R16_MPLL_FAST_LOCK | + PHY_CTRL_R16_MPLL_EN | + PHY_CTRL_R16_MPLL_RESET); + + regmap_write(priv->regmap, PHY_CTRL_R17, + FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) | + FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) | + FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) | + FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | + FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); + + regmap_write(priv->regmap, PHY_CTRL_R18, + FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | + FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | + FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | + FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | + FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | + FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | + FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | + PHY_CTRL_R18_MPLL_ACG_RANGE;
udelay(PLL_RESET_COMPLETE_TIME);
/* UnReset PLL */ - regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414); + regmap_write(priv->regmap, PHY_CTRL_R16, + FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | + FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | + PHY_CTRL_R16_MPLL_LOAD | + FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | + PHY_CTRL_R16_MPLL_FAST_LOCK | + PHY_CTRL_R16_MPLL_EN);
/* PHY Tuning */ - regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18); - regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff); + regmap_write(priv->regmap, PHY_CTRL_R20, + FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) | + PHY_CTRL_R20_USB2_OTG_VBUSDET_EN | + FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) | + PHY_CTRL_R20_USB2_EDGE_DRV_EN | + FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) | + FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) | + FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | + FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); + + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
/* Tuning Disconnect Threshold */ - regmap_write(priv->regmap, PHY_CTRL_R3, 0x34); + regmap_write(priv->regmap, PHY_CTRL_R3, + FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) | + FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) | + FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
/* Analog Settings */ regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | + FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
return 0; }

On 02/10/2023 18:58, Alexey Romanov wrote:
It is better to use defines instead of write raw hex values in regmap.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/phy/meson-g12a-usb2.c | 161 ++++++++++++++++++++++++++++++++-- 1 file changed, 153 insertions(+), 8 deletions(-)
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 650b88bd18..2e366b16ae 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -23,12 +23,28 @@
#include <linux/bitops.h> #include <linux/compat.h> +#include <linux/bitfield.h>
#define PHY_CTRL_R0 0x0 #define PHY_CTRL_R1 0x4 #define PHY_CTRL_R2 0x8
- #define PHY_CTRL_R3 0xc
- #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0)
- #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2)
- #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4)
- #define PHY_CTRL_R4 0x10
- #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0)
- #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8)
- #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16)
- #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24)
- #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25)
- #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26)
- #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27)
- #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28)
- #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30)
- #define PHY_CTRL_R5 0x14 #define PHY_CTRL_R6 0x18 #define PHY_CTRL_R7 0x1c
@@ -37,15 +53,93 @@ #define PHY_CTRL_R10 0x28 #define PHY_CTRL_R11 0x2c #define PHY_CTRL_R12 0x30
- #define PHY_CTRL_R13 0x34
- #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0)
- #define PHY_CTRL_R13_LOAD_STAT BIT(14)
- #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15)
- #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16)
- #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21)
- #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22)
- #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23)
- #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24)
- #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25)
- #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26)
- #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27)
- #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28)
- #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29)
- #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30)
- #define PHY_CTRL_R14 0x38 #define PHY_CTRL_R15 0x3c
- #define PHY_CTRL_R16 0x40
- #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0)
- #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10)
- #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20)
- #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21)
- #define PHY_CTRL_R16_MPLL_LOAD BIT(22)
- #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23)
- #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24)
- #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26)
- #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27)
- #define PHY_CTRL_R16_MPLL_EN BIT(28)
- #define PHY_CTRL_R16_MPLL_RESET BIT(29)
- #define PHY_CTRL_R16_MPLL_LOCK BIT(30)
- #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31)
- #define PHY_CTRL_R17 0x44
- #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0)
- #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16)
- #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17)
- #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20)
- #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23)
- #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24)
- #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28)
- #define PHY_CTRL_R18 0x48
- #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0)
- #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2)
- #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6)
- #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12)
- #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13)
- #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14)
- #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16)
- #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19)
- #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22)
- #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24)
- #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26)
- #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29)
- #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31)
- #define PHY_CTRL_R19 0x4c
- #define PHY_CTRL_R20 0x50
- #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0)
- #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1)
- #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4)
- #define PHY_CTRL_R20_USB2_AMON_EN BIT(5)
- #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6)
- #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7)
- #define PHY_CTRL_R20_USB2_DMON_EN BIT(8)
- #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9)
- #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13)
- #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14)
- #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16)
- #define PHY_CTRL_R20_USB2_BGR_START BIT(21)
- #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24)
- #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29)
- #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31)
- #define PHY_CTRL_R21 0x54
- #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0)
- #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1)
- #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2)
- #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3)
- #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4)
- #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6)
- #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20)
- #define PHY_CTRL_R22 0x58 #define PHY_CTRL_R23 0x5c
@@ -78,25 +172,76 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) regmap_update_bits(priv->regmap, PHY_CTRL_R21, BIT(2), 0);
/* PLL Setup : 24MHz * 20 / 1 = 480MHz */
- regmap_write(priv->regmap, PHY_CTRL_R16, 0x39400414);
- regmap_write(priv->regmap, PHY_CTRL_R17, 0x927e0000);
- regmap_write(priv->regmap, PHY_CTRL_R18, 0xac5f49e5);
regmap_write(priv->regmap, PHY_CTRL_R16,
FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
PHY_CTRL_R16_MPLL_LOAD |
FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
PHY_CTRL_R16_MPLL_FAST_LOCK |
PHY_CTRL_R16_MPLL_EN |
PHY_CTRL_R16_MPLL_RESET);
regmap_write(priv->regmap, PHY_CTRL_R17,
FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) |
FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) |
FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) |
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) |
FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
regmap_write(priv->regmap, PHY_CTRL_R18,
FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) |
FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) |
FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) |
FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) |
FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) |
FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) |
FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) |
FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) |
PHY_CTRL_R18_MPLL_ACG_RANGE;
udelay(PLL_RESET_COMPLETE_TIME);
/* UnReset PLL */
- regmap_write(priv->regmap, PHY_CTRL_R16, 0x19400414);
regmap_write(priv->regmap, PHY_CTRL_R16,
FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) |
FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) |
PHY_CTRL_R16_MPLL_LOAD |
FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) |
PHY_CTRL_R16_MPLL_FAST_LOCK |
PHY_CTRL_R16_MPLL_EN);
/* PHY Tuning */
- regmap_write(priv->regmap, PHY_CTRL_R20, 0xfe18);
- regmap_write(priv->regmap, PHY_CTRL_R4, 0x8000fff);
regmap_write(priv->regmap, PHY_CTRL_R20,
FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) |
PHY_CTRL_R20_USB2_OTG_VBUSDET_EN |
FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) |
PHY_CTRL_R20_USB2_EDGE_DRV_EN |
FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) |
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) |
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) |
FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
regmap_write(priv->regmap, PHY_CTRL_R4,
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
/* Tuning Disconnect Threshold */
- regmap_write(priv->regmap, PHY_CTRL_R3, 0x34);
regmap_write(priv->regmap, PHY_CTRL_R3,
FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) |
FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) |
FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
/* Analog Settings */ regmap_write(priv->regmap, PHY_CTRL_R14, 0);
- regmap_write(priv->regmap, PHY_CTRL_R13, 0x78000);
regmap_write(priv->regmap, PHY_CTRL_R13,
PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
return 0; }
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

It is better to place clk_enable() in phy_meson_g12a_usb2_init() and clk_disable() in phy_meson_g12a_usb2_exit().
For more detailed information, please see comments in the review of a similar driver in the Linux Kernel:
https://lore.kernel.org/all/CAFBinCCEhobbyKHuKDWzTYCQWgNT1-e8=7hMhq1mvT6CuEO...
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/phy/meson-g12a-usb2.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 2e366b16ae..7b028784a0 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -160,6 +160,14 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
+#if CONFIG_IS_ENABLED(CLK) + ret = clk_enable(&priv->clk); + if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { + pr_err("failed to enable PHY clock\n"); + return ret; + } +#endif + ret = reset_assert(&priv->reset); udelay(1); ret |= reset_deassert(&priv->reset); @@ -252,6 +260,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
+#if CONFIG_IS_ENABLED(CLK) + clk_disable(&priv->clk); +#endif + ret = reset_assert(&priv->reset); if (ret) return ret; @@ -289,13 +301,6 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret; - - ret = clk_enable(&priv->clk); - if (ret && ret != -ENOSYS && ret != -ENOTSUPP) { - pr_err("failed to enable PHY clock\n"); - clk_free(&priv->clk); - return ret; - } #endif
return 0;

On 02/10/2023 18:58, Alexey Romanov wrote:
It is better to place clk_enable() in phy_meson_g12a_usb2_init() and clk_disable() in phy_meson_g12a_usb2_exit().
For more detailed information, please see comments in the review of a similar driver in the Linux Kernel:
https://lore.kernel.org/all/CAFBinCCEhobbyKHuKDWzTYCQWgNT1-e8=7hMhq1mvT6CuEO...
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/phy/meson-g12a-usb2.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 2e366b16ae..7b028784a0 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -160,6 +160,14 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
+#if CONFIG_IS_ENABLED(CLK)
- ret = clk_enable(&priv->clk);
- if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
pr_err("failed to enable PHY clock\n");
return ret;
- }
+#endif
- ret = reset_assert(&priv->reset); udelay(1); ret |= reset_deassert(&priv->reset);
@@ -252,6 +260,10 @@ static int phy_meson_g12a_usb2_exit(struct phy *phy) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
+#if CONFIG_IS_ENABLED(CLK)
- clk_disable(&priv->clk);
+#endif
- ret = reset_assert(&priv->reset); if (ret) return ret;
@@ -289,13 +301,6 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) return ret;
ret = clk_enable(&priv->clk);
if (ret && ret != -ENOSYS && ret != -ENOTSUPP) {
pr_err("failed to enable PHY clock\n");
clk_free(&priv->clk);
return ret;
} #endif
return 0;
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

Setting G12A and A1 is similar, so we can use G12A phy driver with little changes.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 77 ++++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cf4d5908d7..60be62907d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -190,7 +190,7 @@ config MESON_GXL_USB_PHY
config MESON_G12A_USB_PHY bool "Amlogic Meson G12A USB PHYs" - depends on PHY && ARCH_MESON && MESON_G12A + depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1) imply REGMAP help This is the generic phy driver for the Amlogic Meson G12A diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 7b028784a0..c1b9baa7b7 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -18,6 +18,7 @@ #include <regmap.h> #include <linux/delay.h> #include <power/regulator.h> +#include <power-domain.h> #include <reset.h> #include <clk.h>
@@ -146,18 +147,28 @@ #define RESET_COMPLETE_TIME 1000 #define PLL_RESET_COMPLETE_TIME 100
+enum meson_soc_id { + MESON_SOC_A1, + MESON_SOC_G12A, +}; + struct phy_meson_g12a_usb2_priv { struct regmap *regmap; #if CONFIG_IS_ENABLED(CLK) struct clk clk; #endif struct reset_ctl reset; +#if CONFIG_IS_ENABLED(POWER_DOMAIN) + struct power_domain pwrdm; +#endif + int soc_id; };
static int phy_meson_g12a_usb2_init(struct phy *phy) { struct udevice *dev = phy->dev; struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); + u32 value; int ret;
#if CONFIG_IS_ENABLED(CLK) @@ -196,8 +207,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
- regmap_write(priv->regmap, PHY_CTRL_R18, - FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | + value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | @@ -209,6 +219,11 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | PHY_CTRL_R18_MPLL_ACG_RANGE;
+ if (priv->soc_id == MESON_SOC_A1) + value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL; + + regmap_write(priv->regmap, PHY_CTRL_R18, value); + udelay(PLL_RESET_COMPLETE_TIME);
/* UnReset PLL */ @@ -231,13 +246,19 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
- regmap_write(priv->regmap, PHY_CTRL_R4, - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | - FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | - PHY_CTRL_R4_TEST_BYPASS_MODE_EN | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | - FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + if (priv->soc_id == MESON_SOC_G12A) + regmap_write(priv->regmap, PHY_CTRL_R4, + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | + FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | + PHY_CTRL_R4_TEST_BYPASS_MODE_EN | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | + FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); + else if (priv->soc_id == MESON_SOC_A1) + regmap_write(priv->regmap, PHY_CTRL_R21, + PHY_CTRL_R21_USB2_CAL_ACK_EN | + PHY_CTRL_R21_USB2_TX_STRG_PD | + FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2));
/* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3, @@ -246,10 +267,15 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
/* Analog Settings */ - regmap_write(priv->regmap, PHY_CTRL_R14, 0); - regmap_write(priv->regmap, PHY_CTRL_R13, - PHY_CTRL_R13_UPDATE_PMA_SIGNALS | - FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + if (priv->soc_id == MESON_SOC_G12A) { + regmap_write(priv->regmap, PHY_CTRL_R14, 0); + regmap_write(priv->regmap, PHY_CTRL_R13, + PHY_CTRL_R13_UPDATE_PMA_SIGNALS | + FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + } else if (priv->soc_id == MESON_SOC_A1) { + regmap_write(priv->regmap, PHY_CTRL_R13, + FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); + }
return 0; } @@ -281,6 +307,8 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
+ priv->soc_id = (enum meson_soc_id)dev_get_driver_data(dev); + ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret; @@ -297,6 +325,20 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) return ret; }
+#if CONFIG_IS_ENABLED(POWER_DOMAIN) + ret = power_domain_get(dev, &priv->pwrdm); + if (ret < 0) { + pr_err("failed to get power domain\n"); + return ret; + } + + ret = power_domain_on(&priv->pwrdm); + if (ret < 0) { + pr_err("failed to enable power domain\n"); + return ret; + } +#endif + #if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0) @@ -307,7 +349,14 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) }
static const struct udevice_id meson_g12a_usb2_phy_ids[] = { - { .compatible = "amlogic,g12a-usb2-phy" }, + { + .compatible = "amlogic,g12a-usb2-phy", + .data = (ulong)MESON_SOC_G12A, + }, + { + .compatible = "amlogic,a1-usb2-phy", + .data = (ulong)MESON_SOC_A1, + }, { } };

On 02/10/2023 18:58, Alexey Romanov wrote:
Setting G12A and A1 is similar, so we can use G12A phy driver with little changes.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/phy/Kconfig | 2 +- drivers/phy/meson-g12a-usb2.c | 77 ++++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 15 deletions(-)
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index cf4d5908d7..60be62907d 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -190,7 +190,7 @@ config MESON_GXL_USB_PHY
config MESON_G12A_USB_PHY bool "Amlogic Meson G12A USB PHYs"
- depends on PHY && ARCH_MESON && MESON_G12A
- depends on PHY && ARCH_MESON && (MESON_G12A || MESON_A1) imply REGMAP help This is the generic phy driver for the Amlogic Meson G12A
diff --git a/drivers/phy/meson-g12a-usb2.c b/drivers/phy/meson-g12a-usb2.c index 7b028784a0..c1b9baa7b7 100644 --- a/drivers/phy/meson-g12a-usb2.c +++ b/drivers/phy/meson-g12a-usb2.c @@ -18,6 +18,7 @@ #include <regmap.h> #include <linux/delay.h> #include <power/regulator.h> +#include <power-domain.h> #include <reset.h> #include <clk.h>
@@ -146,18 +147,28 @@ #define RESET_COMPLETE_TIME 1000 #define PLL_RESET_COMPLETE_TIME 100
+enum meson_soc_id {
- MESON_SOC_A1,
- MESON_SOC_G12A,
+};
- struct phy_meson_g12a_usb2_priv { struct regmap *regmap; #if CONFIG_IS_ENABLED(CLK) struct clk clk; #endif struct reset_ctl reset;
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
- struct power_domain pwrdm;
+#endif
int soc_id; };
static int phy_meson_g12a_usb2_init(struct phy *phy) { struct udevice *dev = phy->dev; struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev);
u32 value; int ret;
#if CONFIG_IS_ENABLED(CLK)
@@ -196,8 +207,7 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9));
- regmap_write(priv->regmap, PHY_CTRL_R18,
FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) |
- value = FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) |
@@ -209,6 +219,11 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | PHY_CTRL_R18_MPLL_ACG_RANGE;
if (priv->soc_id == MESON_SOC_A1)
value |= PHY_CTRL_R18_MPLL_DCO_CLK_SEL;
regmap_write(priv->regmap, PHY_CTRL_R18, value);
udelay(PLL_RESET_COMPLETE_TIME);
/* UnReset PLL */
@@ -231,13 +246,19 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0));
- regmap_write(priv->regmap, PHY_CTRL_R4,
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
if (priv->soc_id == MESON_SOC_G12A)
regmap_write(priv->regmap, PHY_CTRL_R4,
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) |
FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) |
PHY_CTRL_R4_TEST_BYPASS_MODE_EN |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) |
FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0));
else if (priv->soc_id == MESON_SOC_A1)
regmap_write(priv->regmap, PHY_CTRL_R21,
PHY_CTRL_R21_USB2_CAL_ACK_EN |
PHY_CTRL_R21_USB2_TX_STRG_PD |
FIELD_PREP(PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0, 2));
/* Tuning Disconnect Threshold */ regmap_write(priv->regmap, PHY_CTRL_R3,
@@ -246,10 +267,15 @@ static int phy_meson_g12a_usb2_init(struct phy *phy) FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3));
/* Analog Settings */
- regmap_write(priv->regmap, PHY_CTRL_R14, 0);
- regmap_write(priv->regmap, PHY_CTRL_R13,
PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
if (priv->soc_id == MESON_SOC_G12A) {
regmap_write(priv->regmap, PHY_CTRL_R14, 0);
regmap_write(priv->regmap, PHY_CTRL_R13,
PHY_CTRL_R13_UPDATE_PMA_SIGNALS |
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
} else if (priv->soc_id == MESON_SOC_A1) {
regmap_write(priv->regmap, PHY_CTRL_R13,
FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7));
}
return 0; }
@@ -281,6 +307,8 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) struct phy_meson_g12a_usb2_priv *priv = dev_get_priv(dev); int ret;
- priv->soc_id = (enum meson_soc_id)dev_get_driver_data(dev);
- ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret;
@@ -297,6 +325,20 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) return ret; }
+#if CONFIG_IS_ENABLED(POWER_DOMAIN)
- ret = power_domain_get(dev, &priv->pwrdm);
This should be optional, could you ignore on error when power domain is missing ?
Neil
- if (ret < 0) {
pr_err("failed to get power domain\n");
return ret;
- }
- ret = power_domain_on(&priv->pwrdm);
- if (ret < 0) {
pr_err("failed to enable power domain\n");
return ret;
- }
+#endif
- #if CONFIG_IS_ENABLED(CLK) ret = clk_get_by_index(dev, 0, &priv->clk); if (ret < 0)
@@ -307,7 +349,14 @@ int meson_g12a_usb2_phy_probe(struct udevice *dev) }
static const struct udevice_id meson_g12a_usb2_phy_ids[] = {
- { .compatible = "amlogic,g12a-usb2-phy" },
- {
.compatible = "amlogic,g12a-usb2-phy",
.data = (ulong)MESON_SOC_G12A,
- },
- {
.compatible = "amlogic,a1-usb2-phy",
.data = (ulong)MESON_SOC_A1,
- }, { } };

From: Igor Prusov ivprusov@salutedevices.com
We use this clock in dwc3 driver.
Signed-off-by: Igor Prusov ivprusov@salutedevices.com --- drivers/clk/meson/a1.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 3aec42f33b..1540e1875b 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -238,6 +238,9 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1, EXTERNAL_XTAL ), + [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2, + EXTERNAL_XTAL + ), [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8, -ENOENT ),

On 02/10/2023 18:58, Alexey Romanov wrote:
From: Igor Prusov ivprusov@salutedevices.com
We use this clock in dwc3 driver.
Signed-off-by: Igor Prusov ivprusov@salutedevices.com
drivers/clk/meson/a1.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c index 3aec42f33b..1540e1875b 100644 --- a/drivers/clk/meson/a1.c +++ b/drivers/clk/meson/a1.c @@ -238,6 +238,9 @@ static const struct meson_clk_info *meson_clocks[] = { [CLKID_FIXPLL_IN] = CLK_GATE("fixpll_in", A1_SYS_OSCIN_CTRL, 1, EXTERNAL_XTAL ),
- [CLKID_USB_PHY_IN] = CLK_GATE("usb_phy_in", A1_SYS_OSCIN_CTRL, 2,
EXTERNAL_XTAL
- ), [CLKID_SARADC] = CLK_GATE("saradc", A1_SAR_ADC_CLK_CTR, 8, -ENOENT ),
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

Now the driver supports also A1 phy layer.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- drivers/usb/dwc3/dwc3-meson-g12a.c | 73 ++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 90418ddc1d..550e6682a2 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -28,6 +28,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/compat.h> +#include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
/* USB2 Ports Control Registers */
@@ -102,10 +103,22 @@ enum { PHY_COUNT, };
-static const char *phy_names[PHY_COUNT] = { +static const char *const dwc3_meson_g12a_phy_names[] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", };
+static const char *const dwc3_meson_a1_phy_names[] = { + "usb2-phy0", "usb2-phy1" +}; + +struct dwc3_meson_g12a; + +struct dwc3_meson_g12a_drvdata { + const char *const *phy_names; + unsigned int phy_cnt; + int (*clk_init)(struct dwc3_meson_g12a *priv); +}; + struct dwc3_meson_g12a { struct udevice *dev; struct regmap *regmap; @@ -119,6 +132,7 @@ struct dwc3_meson_g12a { #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vbus_supply; #endif + struct dwc3_meson_g12a_drvdata *drvdata; };
#define U2P_REG_SIZE 0x20 @@ -293,10 +307,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) { + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i, ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) { - ret = generic_phy_get_by_name(priv->dev, phy_names[i], + for (i = 0 ; i < data->phy_cnt; ++i) { + ret = generic_phy_get_by_name(priv->dev, data->phy_names[i], &priv->phys[i]); if (ret == -ENOENT || ret == -ENODATA) continue; @@ -354,18 +369,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv) return 0; }
+static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv) +{ + int ret; + + ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk); + if (ret) + return ret; + + ret = clk_enable(&priv->clk); + if (ret) + return ret; + + return 0; +} + static int dwc3_meson_g12a_probe(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = + (struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev); int ret, i;
+ priv->drvdata = data; priv->dev = dev;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret;
- ret = dwc3_meson_g12a_clk_init(priv); + ret = data->clk_init(priv); if (ret) return ret;
@@ -398,7 +431,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) if (ret) return ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -407,7 +440,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) goto err_phy_init; }
- for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -419,7 +452,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) return 0;
err_phy_init: - for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt ; ++i) { if (!priv->phys[i].dev) continue;
@@ -432,20 +465,21 @@ err_phy_init: static int dwc3_meson_g12a_remove(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev); + struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i;
reset_release_all(&priv->reset, 1);
clk_release_all(&priv->clk, 1);
- for (i = 0; i < PHY_COUNT; ++i) { + for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
generic_phy_power_off(&priv->phys[i]); }
- for (i = 0 ; i < PHY_COUNT ; ++i) { + for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -455,8 +489,27 @@ static int dwc3_meson_g12a_remove(struct udevice *dev) return dm_scan_fdt_dev(dev); }
+static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata = { + .phy_names = dwc3_meson_g12a_phy_names, + .phy_cnt = ARRAY_SIZE(dwc3_meson_g12a_phy_names), + .clk_init = dwc3_meson_g12a_clk_init, +}; + +static const struct dwc3_meson_g12a_drvdata meson_a1_drvdata = { + .phy_names = dwc3_meson_a1_phy_names, + .phy_cnt = ARRAY_SIZE(dwc3_meson_a1_phy_names), + .clk_init = dwc3_meson_a1_clk_init, +}; + static const struct udevice_id dwc3_meson_g12a_ids[] = { - { .compatible = "amlogic,meson-g12a-usb-ctrl" }, + { + .compatible = "amlogic,meson-g12a-usb-ctrl", + .data = (ulong)&meson_g12a_drvdata, + }, + { + .compatible = "amlogic,meson-a1-usb-ctrl", + .data = (ulong)&meson_a1_drvdata, + }, { } };

On 02/10/2023 18:58, Alexey Romanov wrote:
Now the driver supports also A1 phy layer.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
drivers/usb/dwc3/dwc3-meson-g12a.c | 73 ++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 10 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c index 90418ddc1d..550e6682a2 100644 --- a/drivers/usb/dwc3/dwc3-meson-g12a.c +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c @@ -28,6 +28,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/compat.h> +#include <dt-bindings/clock/amlogic,a1-peripherals-clkc.h>
/* USB2 Ports Control Registers */
@@ -102,10 +103,22 @@ enum { PHY_COUNT, };
-static const char *phy_names[PHY_COUNT] = { +static const char *const dwc3_meson_g12a_phy_names[] = { "usb2-phy0", "usb2-phy1", "usb3-phy0", };
+static const char *const dwc3_meson_a1_phy_names[] = {
- "usb2-phy0", "usb2-phy1"
+};
+struct dwc3_meson_g12a;
+struct dwc3_meson_g12a_drvdata {
- const char *const *phy_names;
- unsigned int phy_cnt;
- int (*clk_init)(struct dwc3_meson_g12a *priv);
+};
- struct dwc3_meson_g12a { struct udevice *dev; struct regmap *regmap;
@@ -119,6 +132,7 @@ struct dwc3_meson_g12a { #if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vbus_supply; #endif
struct dwc3_meson_g12a_drvdata *drvdata; };
#define U2P_REG_SIZE 0x20
@@ -293,10 +307,11 @@ int dwc3_meson_g12a_force_mode(struct udevice *dev, enum usb_dr_mode mode)
static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) {
- struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i, ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = generic_phy_get_by_name(priv->dev, phy_names[i],
- for (i = 0 ; i < data->phy_cnt; ++i) {
if (ret == -ENOENT || ret == -ENODATA) continue;ret = generic_phy_get_by_name(priv->dev, data->phy_names[i], &priv->phys[i]);
@@ -354,18 +369,36 @@ static int dwc3_meson_g12a_clk_init(struct dwc3_meson_g12a *priv) return 0; }
+static int dwc3_meson_a1_clk_init(struct dwc3_meson_g12a *priv) +{
- int ret;
- ret = clk_get_by_name(priv->dev, "usb_bus", &priv->clk);
- if (ret)
return ret;
- ret = clk_enable(&priv->clk);
- if (ret)
return ret;
- return 0;
+}
static int dwc3_meson_g12a_probe(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev);
struct dwc3_meson_g12a_drvdata *data =
(struct dwc3_meson_g12a_drvdata *)dev_get_driver_data(dev);
int ret, i;
priv->drvdata = data; priv->dev = dev;
ret = regmap_init_mem(dev_ofnode(dev), &priv->regmap); if (ret) return ret;
- ret = dwc3_meson_g12a_clk_init(priv);
- ret = data->clk_init(priv); if (ret) return ret;
@@ -398,7 +431,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) if (ret) return ret;
- for (i = 0 ; i < PHY_COUNT ; ++i) {
- for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -407,7 +440,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) goto err_phy_init; }
- for (i = 0; i < PHY_COUNT; ++i) {
- for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -419,7 +452,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev) return 0;
err_phy_init:
- for (i = 0 ; i < PHY_COUNT ; ++i) {
- for (i = 0 ; i < data->phy_cnt ; ++i) { if (!priv->phys[i].dev) continue;
@@ -432,20 +465,21 @@ err_phy_init: static int dwc3_meson_g12a_remove(struct udevice *dev) { struct dwc3_meson_g12a *priv = dev_get_plat(dev);
struct dwc3_meson_g12a_drvdata *data = priv->drvdata; int i;
reset_release_all(&priv->reset, 1);
clk_release_all(&priv->clk, 1);
- for (i = 0; i < PHY_COUNT; ++i) {
for (i = 0; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
generic_phy_power_off(&priv->phys[i]); }
- for (i = 0 ; i < PHY_COUNT ; ++i) {
- for (i = 0 ; i < data->phy_cnt; ++i) { if (!priv->phys[i].dev) continue;
@@ -455,8 +489,27 @@ static int dwc3_meson_g12a_remove(struct udevice *dev) return dm_scan_fdt_dev(dev); }
+static const struct dwc3_meson_g12a_drvdata meson_g12a_drvdata = {
- .phy_names = dwc3_meson_g12a_phy_names,
- .phy_cnt = ARRAY_SIZE(dwc3_meson_g12a_phy_names),
- .clk_init = dwc3_meson_g12a_clk_init,
+};
+static const struct dwc3_meson_g12a_drvdata meson_a1_drvdata = {
- .phy_names = dwc3_meson_a1_phy_names,
- .phy_cnt = ARRAY_SIZE(dwc3_meson_a1_phy_names),
- .clk_init = dwc3_meson_a1_clk_init,
+};
- static const struct udevice_id dwc3_meson_g12a_ids[] = {
- { .compatible = "amlogic,meson-g12a-usb-ctrl" },
- {
.compatible = "amlogic,meson-g12a-usb-ctrl",
.data = (ulong)&meson_g12a_drvdata,
- },
- {
.compatible = "amlogic,meson-a1-usb-ctrl",
.data = (ulong)&meson_a1_drvdata,
- }, { } };
Reviewed-by: Neil Armstrong neil.armstrong@linaro.org

This is entrypoint for USB stack initialization. Function board_usb_init will be called from cmd/fastboot.c code.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com --- arch/arm/mach-meson/board-a1.c | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
diff --git a/arch/arm/mach-meson/board-a1.c b/arch/arm/mach-meson/board-a1.c index 967bb67182..781d5cfb33 100644 --- a/arch/arm/mach-meson/board-a1.c +++ b/arch/arm/mach-meson/board-a1.c @@ -4,12 +4,17 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h> #include <asm/arch/a1.h> #include <asm/arch/boot.h> #include <asm/armv8/mmu.h> #include <asm/io.h> #include <linux/compiler.h> #include <linux/sizes.h> +#include <linux/usb/otg.h> +#include <asm/arch/usb.h> +#include <usb/dwc2_udc.h>
phys_size_t get_effective_memsize(void) { @@ -57,3 +62,87 @@ static struct mm_region a1_mem_map[] = { };
struct mm_region *mem_map = a1_mem_map; + +#if CONFIG_IS_ENABLED(USB_DWC3_MESON_G12A) && \ + CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG) + +static struct dwc2_plat_otg_data meson_a1_dwc2_data; + +int board_usb_init(int index, enum usb_init_type init) +{ + int node, dwc2_node; + const void *blob = gd->fdt_blob; + struct udevice *dev; + int ret; + + node = fdt_node_offset_by_compatible(blob, -1, + "amlogic,meson-a1-usb-ctrl"); + if (node < 0) { + pr_err("not found usb-control node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, node)) { + pr_err("usb is disabled in the device tree\n"); + return -ENODEV; + } + + ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev); + if (ret) { + pr_err("not found usb-control device\n"); + return ret; + } + + dwc2_node = fdt_node_offset_by_compatible(blob, node, + "amlogic,meson-a1-usb"); + if (dwc2_node < 0) { + pr_err("not found dwc2 node\n"); + return -ENODEV; + } + + if (!fdtdec_get_is_enabled(blob, dwc2_node)) { + pr_err("dwc2 is disabled in the device tree\n"); + return -ENODEV; + } + + meson_a1_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg"); + if (meson_a1_dwc2_data.regs_otg == FDT_ADDR_T_NONE) { + pr_err("can't get base address\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-rx-fifo-size", 0); + if (meson_a1_dwc2_data.rx_fifo_sz < 0) { + pr_err("failed to get g-rx-fifo-size value\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-np-tx-fifo-size", 0); + if (meson_a1_dwc2_data.np_tx_fifo_sz < 0) { + pr_err("failed to get g-np-tx-fifo-size value\n"); + return -ENODATA; + } + + meson_a1_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node, + "g-tx-fifo-size", 0); + if (meson_a1_dwc2_data.tx_fifo_sz < 0) { + pr_err("failed to get g-tx-fifo-size value\n"); + return -ENODATA; + } + + ret = dwc3_meson_g12a_force_mode(dev, USB_DR_MODE_PERIPHERAL); + if (ret) { + pr_err("failed to force usb mode to peripheral\n"); + return ret; + } + + return dwc2_udc_probe(&meson_a1_dwc2_data); +} + +int board_usb_cleanup(int index, enum usb_init_type init) +{ + return 0; +} +#endif

Hi,
On 02/10/2023 18:58, Alexey Romanov wrote:
This is entrypoint for USB stack initialization. Function board_usb_init will be called from cmd/fastboot.c code.
This should not be needed anymore, using DM_USB_GADGET should work, look how it was changed for G12A/SM1 and GXL/AXG: https://lore.kernel.org/all/20221024-meson-dm-usb-v1-0-2ab077a503b9@baylibre... and https://lore.kernel.org/all/20230117-u-boot-usb-gxl-otg-dm-v1-0-2853f6d75b06...
Neil
Signed-off-by: Alexey Romanov avromanov@salutedevices.com
arch/arm/mach-meson/board-a1.c | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+)
diff --git a/arch/arm/mach-meson/board-a1.c b/arch/arm/mach-meson/board-a1.c index 967bb67182..781d5cfb33 100644 --- a/arch/arm/mach-meson/board-a1.c +++ b/arch/arm/mach-meson/board-a1.c @@ -4,12 +4,17 @@ */
#include <common.h> +#include <dm.h> +#include <usb.h> #include <asm/arch/a1.h> #include <asm/arch/boot.h> #include <asm/armv8/mmu.h> #include <asm/io.h> #include <linux/compiler.h> #include <linux/sizes.h> +#include <linux/usb/otg.h> +#include <asm/arch/usb.h> +#include <usb/dwc2_udc.h>
phys_size_t get_effective_memsize(void) { @@ -57,3 +62,87 @@ static struct mm_region a1_mem_map[] = { };
struct mm_region *mem_map = a1_mem_map;
+#if CONFIG_IS_ENABLED(USB_DWC3_MESON_G12A) && \
- CONFIG_IS_ENABLED(USB_GADGET_DWC2_OTG)
+static struct dwc2_plat_otg_data meson_a1_dwc2_data;
+int board_usb_init(int index, enum usb_init_type init) +{
- int node, dwc2_node;
- const void *blob = gd->fdt_blob;
- struct udevice *dev;
- int ret;
- node = fdt_node_offset_by_compatible(blob, -1,
"amlogic,meson-a1-usb-ctrl");
- if (node < 0) {
pr_err("not found usb-control node\n");
return -ENODEV;
- }
- if (!fdtdec_get_is_enabled(blob, node)) {
pr_err("usb is disabled in the device tree\n");
return -ENODEV;
- }
- ret = uclass_get_device_by_of_offset(UCLASS_SIMPLE_BUS, node, &dev);
- if (ret) {
pr_err("not found usb-control device\n");
return ret;
- }
- dwc2_node = fdt_node_offset_by_compatible(blob, node,
"amlogic,meson-a1-usb");
- if (dwc2_node < 0) {
pr_err("not found dwc2 node\n");
return -ENODEV;
- }
- if (!fdtdec_get_is_enabled(blob, dwc2_node)) {
pr_err("dwc2 is disabled in the device tree\n");
return -ENODEV;
- }
- meson_a1_dwc2_data.regs_otg = fdtdec_get_addr(blob, dwc2_node, "reg");
- if (meson_a1_dwc2_data.regs_otg == FDT_ADDR_T_NONE) {
pr_err("can't get base address\n");
return -ENODATA;
- }
- meson_a1_dwc2_data.rx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
"g-rx-fifo-size", 0);
- if (meson_a1_dwc2_data.rx_fifo_sz < 0) {
pr_err("failed to get g-rx-fifo-size value\n");
return -ENODATA;
- }
- meson_a1_dwc2_data.np_tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
"g-np-tx-fifo-size", 0);
- if (meson_a1_dwc2_data.np_tx_fifo_sz < 0) {
pr_err("failed to get g-np-tx-fifo-size value\n");
return -ENODATA;
- }
- meson_a1_dwc2_data.tx_fifo_sz = fdtdec_get_int(blob, dwc2_node,
"g-tx-fifo-size", 0);
- if (meson_a1_dwc2_data.tx_fifo_sz < 0) {
pr_err("failed to get g-tx-fifo-size value\n");
return -ENODATA;
- }
- ret = dwc3_meson_g12a_force_mode(dev, USB_DR_MODE_PERIPHERAL);
- if (ret) {
pr_err("failed to force usb mode to peripheral\n");
return ret;
- }
- return dwc2_udc_probe(&meson_a1_dwc2_data);
+}
+int board_usb_cleanup(int index, enum usb_init_type init) +{
- return 0;
+} +#endif
participants (2)
-
Alexey Romanov
-
neil.armstrong@linaro.org