From e1bca7c77d80b3f35f5045cd8983349819165f1e Mon Sep 17 00:00:00 2001 From: Birger Koblitz Date: Thu, 21 Jan 2021 15:09:47 +0100 Subject: [PATCH] realtek: fix RTL8231 gpio expander usage with RTL839X SoC This fixes the usage of the RTL8231 GPIO extender chip when used with the RTL839X SoCs. Specifically, the PHY addresses may be different from 0. Signed-off-by: Birger Koblitz --- .../files-5.4/drivers/gpio/gpio-rtl8231.c | 64 ++++++++++++------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c b/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c index be5efc2997..031f60f530 100644 --- a/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c +++ b/target/linux/realtek/files-5.4/drivers/gpio/gpio-rtl8231.c @@ -12,6 +12,8 @@ #define RTL8231_GPIO_DIR(gpio) ((0x0005) + ((gpio) >> 4)) #define RTL8231_GPIO_DATA(gpio) ((0x001C) + ((gpio) >> 4)) +#define USEC_TIMEOUT 5000 + struct rtl8231_gpios { struct gpio_chip gc; struct device *dev; @@ -27,7 +29,7 @@ extern struct rtl83xx_soc_info soc_info; static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) { - u32 t = 0; + u32 t = 0, n = 0; u8 bus_id = gpios->smi_bus_id; reg &= 0x1f; @@ -38,10 +40,18 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) /* Set execution bit: cleared when operation completed */ t |= 1; + + // Start execution sw_w32(t, gpios->ext_gpio_indrt_access); - do { /* TODO: Return 0x80000000 if timeout */ + do { + udelay(1); t = sw_r32(gpios->ext_gpio_indrt_access); - } while (t & 1); + n++; + } while ((t & 1) && (n < USEC_TIMEOUT)); + + if (n >= USEC_TIMEOUT) + return 0x80000000; + pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, (t & 0xffff0000) >> 16); return (t & 0xffff0000) >> 16; @@ -49,7 +59,7 @@ static u32 rtl8231_read(struct rtl8231_gpios *gpios, u32 reg) static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data) { - u32 t = 0; + u32 t = 0, n = 0; u8 bus_id = gpios->smi_bus_id; pr_debug("%s: %x, %x, %x\n", __func__, bus_id, reg, data); @@ -62,10 +72,16 @@ static int rtl8231_write(struct rtl8231_gpios *gpios, u32 reg, u32 data) /* Set execution bit: cleared when operation completed */ t |= 1; + + // Start execution sw_w32(t, gpios->ext_gpio_indrt_access); - do { /* TODO: Return -1 if timeout */ + do { + udelay(1); t = sw_r32(gpios->ext_gpio_indrt_access); - } while (t & 1); + } while ((t & 1) && (n < USEC_TIMEOUT)); + + if (n >= USEC_TIMEOUT) + return -1; return 0; } @@ -94,7 +110,7 @@ static int rtl8231_pin_dir(struct rtl8231_gpios *gpios, u32 gpio, u32 dir) int dpin = pin; if (gpio > 31) { - pr_info("WARNING: HIGH pin\n"); + pr_debug("WARNING: HIGH pin\n"); dpin = pin << 5; pin_dir_addr = pin_sel_addr; } @@ -226,26 +242,21 @@ int rtl8231_init(struct rtl8231_gpios *gpios) { pr_info("%s called, MDIO bus ID: %d\n", __func__, gpios->smi_bus_id); + gpios->reg_cached = 0; + if (soc_info.family == RTL8390_FAMILY_ID) { + // RTL8390: Enable external gpio in global led control register sw_w32_mask(0x7 << 18, 0x4 << 18, RTL839X_LED_GLB_CTRL); - return 0; + } else if (soc_info.family == RTL8380_FAMILY_ID) { + // RTL8380: Enable RTL8231 indirect access mode + sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL); + sw_w32_mask(3, 1, RTL838X_DMY_REG5); } - /* Enable RTL8231 indirect access mode */ - sw_w32_mask(0, 1, RTL838X_EXTRA_GPIO_CTRL); - sw_w32_mask(3, 1, RTL838X_DMY_REG5); - - /* Enable RTL8231 via GPIO_A1 line - rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DIR); - rtl838x_w32_mask(0, 1 << RTL838X_GPIO_A1, RTL838X_GPIO_PABC_DATA); */ - mdelay(50); /* wait 50ms for reset */ - /*Select GPIO functionality for pins 0-15, 16-31 and 32-37 */ rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(0), 0xffff); rtl8231_write(gpios, RTL8231_GPIO_PIN_SEL(16), 0xffff); - gpios->reg_cached = 0; - return 0; } @@ -262,7 +273,7 @@ static int rtl8231_gpio_probe(struct platform_device *pdev) struct device_node *np = dev->of_node; struct rtl8231_gpios *gpios; int err; - u8 indirect_bus_id; + u32 indirect_bus_id; pr_info("Probing RTL8231 GPIOs\n"); @@ -284,10 +295,15 @@ static int rtl8231_gpio_probe(struct platform_device *pdev) gpios->ext_gpio_indrt_access = RTL839X_EXT_GPIO_INDRT_ACCESS; } - if (!of_property_read_u8(np, "indirect-access-bus-id", &indirect_bus_id)) { - gpios->smi_bus_id = indirect_bus_id; - rtl8231_init(gpios); - } + /* + * We use a default MDIO bus ID for the 8231 of 0, which can be overriden + * by the indirect-access-bus-id property in the dts. + */ + gpios->smi_bus_id = 0; + of_property_read_u32(np, "indirect-access-bus-id", &indirect_bus_id); + gpios->smi_bus_id = indirect_bus_id; + + rtl8231_init(gpios); gpios->dev = dev; gpios->gc.base = 160; -- 2.30.2