diff mbox series

[08/14] pinctrl: renesas: rzg2l: Add output enable support

Message ID 20231120070024.4079344-9-claudiu.beznea.uj@bp.renesas.com
State New
Headers show
Series renesas: rzg3s: Add support for Ethernet | expand

Commit Message

Claudiu Nov. 20, 2023, 7 a.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Some of the Ethernet pins on RZ/G3S (but also valid for RZ/G2L) need to
have direction of the IO buffer set as output for Ethernet to work
properly. On RZ/G3S these pins are P1_0/P7_0, P1_1/P7_1 with could have
the following Ethernet functions: TXC/TX_CLK or TX_CTL/TX_EN. To be able
to configure this the output enable has been implemented. This is
implemented with 2 per-platform read/write functions to be able to simply
validate the pins supporting this on a platform basis. Moreover, on RZ/G2L
the register though which these settings could be done is 8 bits long
whereas on RZ/G3S this is a 32 bit register. The Ethernet pins supporting
OEN are different. These differences could be handled in platform specific
OEN read/write functions.

Add support for OEN and enable it for RZ/G3S.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 drivers/pinctrl/renesas/pinctrl-rzg2l.c | 106 +++++++++++++++++++++++-
 1 file changed, 104 insertions(+), 2 deletions(-)

Comments

Geert Uytterhoeven Dec. 1, 2023, 5:25 p.m. UTC | #1
Hi Claudiu,

Thanks for your patch!

On Mon, Nov 20, 2023 at 8:01 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> Some of the Ethernet pins on RZ/G3S (but also valid for RZ/G2L) need to
> have direction of the IO buffer set as output for Ethernet to work
> properly. On RZ/G3S these pins are P1_0/P7_0, P1_1/P7_1 with could have
> the following Ethernet functions: TXC/TX_CLK or TX_CTL/TX_EN. To be able
> to configure this the output enable has been implemented. This is
> implemented with 2 per-platform read/write functions to be able to simply
> validate the pins supporting this on a platform basis. Moreover, on RZ/G2L
> the register though which these settings could be done is 8 bits long
> whereas on RZ/G3S this is a 32 bit register. The Ethernet pins supporting
> OEN are different. These differences could be handled in platform specific
> OEN read/write functions.

These registers are documented to support access sizes of 8/16/32 bits
on RZ/G3S.  Hence you don't need to differentiate, but can just use
8-bit accesses on all platforms.

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
diff mbox series

Patch

diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
index 1401bb215686..e942204e08a2 100644
--- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c
+++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c
@@ -57,6 +57,7 @@ 
 #define PIN_CFG_FILCLKSEL		BIT(12)
 #define PIN_CFG_IOLH_C			BIT(13)
 #define PIN_CFG_SOFT_PS			BIT(14)
+#define PIN_CFG_OEN			BIT(15)
 
 #define RZG2L_MPXED_COMMON_PIN_FUNCS(group) \
 					(PIN_CFG_IOLH_##group | \
@@ -109,6 +110,7 @@ 
 #define SD_CH(off, ch)		((off) + (ch) * 4)
 #define ETH_POC(off, ch)	((off) + (ch) * 4)
 #define QSPI			(0x3008)
+#define ETH_MODE		(0x3018)
 
 #define PVDD_2500		2	/* I/O domain voltage 2.5V */
 #define PVDD_1800		1	/* I/O domain voltage <= 1.8V */
@@ -195,6 +197,7 @@  struct rzg2l_pinctrl_data {
 	unsigned int n_port_pins;
 	unsigned int n_dedicated_pins;
 	const struct rzg2l_hwcfg *hwcfg;
+	const struct rzg2l_cfg_ops *ops;
 };
 
 /**
@@ -228,6 +231,16 @@  struct rzg2l_pinctrl {
 	struct rzg2l_pinctrl_pin_settings *settings;
 };
 
+/*
+ * struct rzg2l_cfg_ops - platform specific configuration ops
+ * @read_oen: read OEN function
+ * @write_oen: write OEN function
+ */
+struct rzg2l_cfg_ops {
+	u32 (*read_oen)(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin);
+	int (*write_oen)(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen);
+};
+
 static const u16 available_ps[] = { 1800, 2500, 3300 };
 
 static void rzg2l_pinctrl_set_pfc_mode(struct rzg2l_pinctrl *pctrl,
@@ -776,6 +789,67 @@  static bool rzg2l_ds_is_supported(struct rzg2l_pinctrl *pctrl, u32 caps,
 	return false;
 }
 
+static bool rzg3s_oen_is_supported(u32 caps, u8 pin)
+{
+	if (!(caps & PIN_CFG_OEN))
+		return false;
+
+	/*
+	 * Only pins 0 and 1 of P1 and P7 are supporting this thus add a simple
+	 * check for this here.
+	 */
+	if (pin > 1)
+		return false;
+
+	return true;
+}
+
+static u8 rzg3s_pin_to_oen_bit(u32 offset, u8 pin)
+{
+	if (pin)
+		pin *= 2;
+
+	if (offset / RZG2L_PINS_PER_PORT == 7)
+		pin += 1;
+
+	return pin;
+}
+
+static u32 rzg3s_read_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin)
+{
+	u8 bit;
+
+	if (!rzg3s_oen_is_supported(caps, pin))
+		return 0;
+
+	bit = rzg3s_pin_to_oen_bit(offset, pin);
+
+	return !(readl(pctrl->base + ETH_MODE) & BIT(bit));
+}
+
+static int rzg3s_write_oen(struct rzg2l_pinctrl *pctrl, u32 caps, u32 offset, u8 pin, u8 oen)
+{
+	unsigned long flags;
+	u32 val;
+	u8 bit;
+
+	if (!rzg3s_oen_is_supported(caps, pin))
+		return -EINVAL;
+
+	bit = rzg3s_pin_to_oen_bit(offset, pin);
+
+	spin_lock_irqsave(&pctrl->lock, flags);
+	val = readl(pctrl->base + ETH_MODE);
+	if (oen)
+		val &= ~BIT(bit);
+	else
+		val |= BIT(bit);
+	writel(val, pctrl->base + ETH_MODE);
+	spin_unlock_irqrestore(&pctrl->lock, flags);
+
+	return 0;
+}
+
 static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
 				     unsigned int _pin,
 				     unsigned long *config)
@@ -813,6 +887,16 @@  static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
 			return -EINVAL;
 		break;
 
+	case PIN_CONFIG_OUTPUT_ENABLE:
+		if (!(pctrl->data->ops && pctrl->data->ops->read_oen))
+			return -EINVAL;
+
+		arg = pctrl->data->ops->read_oen(pctrl, cfg, _pin, bit);
+		if (!arg)
+			return -EINVAL;
+
+		break;
+
 	case PIN_CONFIG_POWER_SOURCE:
 		ret = rzg2l_get_power_source(pctrl, _pin, cfg);
 		if (ret < 0)
@@ -915,6 +999,16 @@  static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
 			break;
 		}
 
+		case PIN_CONFIG_OUTPUT_ENABLE:
+			if (!(pctrl->data->ops && pctrl->data->ops->write_oen))
+				return -EINVAL;
+
+			arg = pinconf_to_config_argument(_configs[i]);
+			ret = pctrl->data->ops->write_oen(pctrl, cfg, _pin, bit, !!arg);
+			if (ret)
+				return ret;
+			break;
+
 		case PIN_CONFIG_POWER_SOURCE:
 			settings.power_source = pinconf_to_config_argument(_configs[i]);
 			break;
@@ -1365,7 +1459,8 @@  static const u32 r9a07g043_gpio_configs[] = {
 static const u32 r9a08g045_gpio_configs[] = {
 	RZG2L_GPIO_PORT_PACK(4, 0x20, RZG3S_MPXED_PIN_FUNCS(A)),			/* P0  */
 	RZG2L_GPIO_PORT_PACK(5, 0x30, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
-								PIN_CFG_IO_VMC_ETH0)),	/* P1 */
+								PIN_CFG_IO_VMC_ETH0)) |
+				      PIN_CFG_IEN | PIN_CFG_OEN,			/* P1 */
 	RZG2L_GPIO_PORT_PACK(4, 0x31, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
 								PIN_CFG_IO_VMC_ETH0)),	/* P2 */
 	RZG2L_GPIO_PORT_PACK(4, 0x32, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1375,7 +1470,8 @@  static const u32 r9a08g045_gpio_configs[] = {
 	RZG2L_GPIO_PORT_PACK(5, 0x21, RZG3S_MPXED_PIN_FUNCS(A)),			/* P5  */
 	RZG2L_GPIO_PORT_PACK(5, 0x22, RZG3S_MPXED_PIN_FUNCS(A)),			/* P6  */
 	RZG2L_GPIO_PORT_PACK(5, 0x34, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
-								PIN_CFG_IO_VMC_ETH1)),	/* P7 */
+								PIN_CFG_IO_VMC_ETH1)) |
+				      PIN_CFG_IEN | PIN_CFG_OEN,			/* P7 */
 	RZG2L_GPIO_PORT_PACK(5, 0x35, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
 								PIN_CFG_IO_VMC_ETH1)),	/* P8 */
 	RZG2L_GPIO_PORT_PACK(4, 0x36, RZG2L_MPXED_ETH_PIN_FUNCS(PIN_CFG_IOLH_C |
@@ -1958,6 +2054,11 @@  static const struct rzg2l_hwcfg rzg3s_hwcfg = {
 	.func_base = 1,
 };
 
+static const struct rzg2l_cfg_ops rzg3s_ops = {
+	.read_oen = rzg3s_read_oen,
+	.write_oen = rzg3s_write_oen,
+};
+
 static struct rzg2l_pinctrl_data r9a07g043_data = {
 	.port_pins = rzg2l_gpio_names,
 	.port_pin_configs = r9a07g043_gpio_configs,
@@ -1987,6 +2088,7 @@  static struct rzg2l_pinctrl_data r9a08g045_data = {
 	.n_port_pins = ARRAY_SIZE(r9a08g045_gpio_configs) * RZG2L_PINS_PER_PORT,
 	.n_dedicated_pins = ARRAY_SIZE(rzg3s_dedicated_pins),
 	.hwcfg = &rzg3s_hwcfg,
+	.ops = &rzg3s_ops,
 };
 
 static const struct of_device_id rzg2l_pinctrl_of_table[] = {