diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/nuvoton/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/nuvoton/clk_npcm8xx.c | 98 | ||||
-rw-r--r-- | drivers/dma/ti/k3-udma.c | 1 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 6 | ||||
-rw-r--r-- | drivers/gpio/Makefile | 1 | ||||
-rw-r--r-- | drivers/gpio/ftgpio010.c | 111 | ||||
-rw-r--r-- | drivers/net/ti/am65-cpsw-nuss.c | 24 | ||||
-rw-r--r-- | drivers/net/ti/cpsw.c | 3 | ||||
-rw-r--r-- | drivers/net/ti/cpsw_mdio.c | 255 | ||||
-rw-r--r-- | drivers/net/ti/cpsw_mdio.h | 2 | ||||
-rw-r--r-- | drivers/net/ti/keystone_net.c | 3 |
11 files changed, 497 insertions, 8 deletions
diff --git a/drivers/clk/nuvoton/Makefile b/drivers/clk/nuvoton/Makefile index c63d9c16f1..b55dc80de2 100644 --- a/drivers/clk/nuvoton/Makefile +++ b/drivers/clk/nuvoton/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ARCH_NPCM) += clk_npcm.o obj-$(CONFIG_ARCH_NPCM7xx) += clk_npcm7xx.o +obj-$(CONFIG_ARCH_NPCM8XX) += clk_npcm8xx.o diff --git a/drivers/clk/nuvoton/clk_npcm8xx.c b/drivers/clk/nuvoton/clk_npcm8xx.c new file mode 100644 index 0000000000..27e3cfcf55 --- /dev/null +++ b/drivers/clk/nuvoton/clk_npcm8xx.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022 Nuvoton Technology Corp. + */ + +#include <dm.h> +#include <dt-bindings/clock/nuvoton,npcm845-clk.h> +#include "clk_npcm.h" + +/* Parent clock map */ +static const struct parent_data pll_parents[] = { + {NPCM8XX_CLK_PLL0, 0}, + {NPCM8XX_CLK_PLL1, 1}, + {NPCM8XX_CLK_REFCLK, 2}, + {NPCM8XX_CLK_PLL2DIV2, 3} +}; + +static const struct parent_data cpuck_parents[] = { + {NPCM8XX_CLK_PLL0, 0}, + {NPCM8XX_CLK_PLL1, 1}, + {NPCM8XX_CLK_REFCLK, 2}, + {NPCM8XX_CLK_PLL2, 7} +}; + +static const struct parent_data apb_parent[] = {{NPCM8XX_CLK_AHB, 0}}; + +static struct npcm_clk_pll npcm8xx_clk_plls[] = { + {NPCM8XX_CLK_PLL0, NPCM8XX_CLK_REFCLK, PLLCON0, 0}, + {NPCM8XX_CLK_PLL1, NPCM8XX_CLK_REFCLK, PLLCON1, 0}, + {NPCM8XX_CLK_PLL2, NPCM8XX_CLK_REFCLK, PLLCON2, 0}, + {NPCM8XX_CLK_PLL2DIV2, NPCM8XX_CLK_REFCLK, PLLCON2, POST_DIV2} +}; + +static struct npcm_clk_select npcm8xx_clk_selectors[] = { + {NPCM8XX_CLK_AHB, cpuck_parents, CLKSEL, NPCM8XX_CPUCKSEL, 4, 0}, + {NPCM8XX_CLK_APB2, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_APB5, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_SPI0, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_SPI1, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_SPI3, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_SPIX, apb_parent, 0, 0, 1, FIXED_PARENT}, + {NPCM8XX_CLK_UART, pll_parents, CLKSEL, UARTCKSEL, 4, 0}, + {NPCM8XX_CLK_UART2, pll_parents, CLKSEL, UARTCKSEL, 4, 0}, + {NPCM8XX_CLK_SDHC, pll_parents, CLKSEL, SDCKSEL, 4, 0} +}; + +static struct npcm_clk_div npcm8xx_clk_dividers[] = { + {NPCM8XX_CLK_AHB, CLKDIV1, CLK4DIV, DIV_TYPE1 | PRE_DIV2}, + {NPCM8XX_CLK_APB2, CLKDIV2, APB2CKDIV, DIV_TYPE2}, + {NPCM8XX_CLK_APB5, CLKDIV2, APB5CKDIV, DIV_TYPE2}, + {NPCM8XX_CLK_SPI0, CLKDIV3, SPI0CKDIV, DIV_TYPE1}, + {NPCM8XX_CLK_SPI1, CLKDIV3, SPI1CKDIV, DIV_TYPE1}, + {NPCM8XX_CLK_SPI3, CLKDIV1, SPI3CKDIV, DIV_TYPE1}, + {NPCM8XX_CLK_SPIX, CLKDIV3, SPIXCKDIV, DIV_TYPE1}, + {NPCM8XX_CLK_UART, CLKDIV1, UARTDIV1, DIV_TYPE1}, + {NPCM8XX_CLK_UART2, CLKDIV3, UARTDIV2, DIV_TYPE1}, + {NPCM8XX_CLK_SDHC, CLKDIV1, MMCCKDIV, DIV_TYPE1} +}; + +static struct npcm_clk_data npcm8xx_clk_data = { + .clk_plls = npcm8xx_clk_plls, + .num_plls = ARRAY_SIZE(npcm8xx_clk_plls), + .clk_selectors = npcm8xx_clk_selectors, + .num_selectors = ARRAY_SIZE(npcm8xx_clk_selectors), + .clk_dividers = npcm8xx_clk_dividers, + .num_dividers = ARRAY_SIZE(npcm8xx_clk_dividers), + .refclk_id = NPCM8XX_CLK_REFCLK, + .pll0_id = NPCM8XX_CLK_PLL0, +}; + +static int npcm8xx_clk_probe(struct udevice *dev) +{ + struct npcm_clk_priv *priv = dev_get_priv(dev); + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + priv->clk_data = &npcm8xx_clk_data; + priv->num_clks = NPCM8XX_NUM_CLOCKS; + + return 0; +} + +static const struct udevice_id npcm8xx_clk_ids[] = { + { .compatible = "nuvoton,npcm845-clk" }, + { } +}; + +U_BOOT_DRIVER(clk_npcm) = { + .name = "clk_npcm", + .id = UCLASS_CLK, + .of_match = npcm8xx_clk_ids, + .ops = &npcm_clk_ops, + .priv_auto = sizeof(struct npcm_clk_priv), + .probe = npcm8xx_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c index 86603d43f1..1a9197bfc8 100644 --- a/drivers/dma/ti/k3-udma.c +++ b/drivers/dma/ti/k3-udma.c @@ -14,6 +14,7 @@ #include <malloc.h> #include <linux/bitops.h> #include <linux/dma-mapping.h> +#include <linux/sizes.h> #include <dm.h> #include <dm/device_compat.h> #include <dm/devres.h> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index c949f9d2f7..2a60478b47 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -605,4 +605,10 @@ config TURRIS_OMNIA_MCU help Support for GPIOs on MCU connected to Turris Omnia via i2c. +config FTGPIO010 + bool "Faraday Technology FTGPIO010 driver" + depends on DM_GPIO + help + Support for GPIOs on Faraday Technology's FTGPIO010 controller. + endif diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 9d718a554e..eee7908871 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -75,3 +75,4 @@ obj-$(CONFIG_SL28CPLD_GPIO) += sl28cpld-gpio.o obj-$(CONFIG_ZYNQMP_GPIO_MODEPIN) += zynqmp_gpio_modepin.o obj-$(CONFIG_SLG7XL45106_I2C_GPO) += gpio_slg7xl45106.o obj-$(CONFIG_$(SPL_TPL_)TURRIS_OMNIA_MCU) += turris_omnia_mcu.o +obj-$(CONFIG_FTGPIO010) += ftgpio010.o diff --git a/drivers/gpio/ftgpio010.c b/drivers/gpio/ftgpio010.c new file mode 100644 index 0000000000..6c091d4fd8 --- /dev/null +++ b/drivers/gpio/ftgpio010.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Faraday Technology's FTGPIO010 controller. + */ + +#include <common.h> +#include <dm.h> +#include <asm/io.h> +#include <asm/gpio.h> + +struct ftgpio010_regs { + u32 out; + u32 in; + u32 direction; // 1 - output + u32 reserved; + u32 set; + u32 clear; +}; + +struct ftgpio010_plat { + struct ftgpio010_regs __iomem *regs; +}; + +static int ftgpio010_direction_input(struct udevice *dev, unsigned int pin) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + struct ftgpio010_regs *const regs = plat->regs; + + clrbits_le32(®s->direction, 1 << pin); + return 0; +} + +static int ftgpio010_direction_output(struct udevice *dev, unsigned int pin, + int val) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + struct ftgpio010_regs *const regs = plat->regs; + + /* change the data first, then the direction. to avoid glitch */ + out_le32(val ? ®s->set : ®s->clear, 1 << pin); + setbits_le32(®s->direction, 1 << pin); + + return 0; +} + +static int ftgpio010_get_value(struct udevice *dev, unsigned int pin) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + struct ftgpio010_regs *const regs = plat->regs; + + return in_le32(®s->in) >> pin & 1; +} + +static int ftgpio010_set_value(struct udevice *dev, unsigned int pin, int val) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + struct ftgpio010_regs *const regs = plat->regs; + + out_le32(val ? ®s->set : ®s->clear, 1 << pin); + return 0; +} + +static int ftgpio010_get_function(struct udevice *dev, unsigned int pin) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + struct ftgpio010_regs *const regs = plat->regs; + + if (in_le32(®s->direction) >> pin & 1) + return GPIOF_OUTPUT; + return GPIOF_INPUT; +} + +static int ftgpio010_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = ofnode_read_u32_default(dev_ofnode(dev), + "nr-gpios", 32); + return 0; +} + +static int ftgpio010_of_to_plat(struct udevice *dev) +{ + struct ftgpio010_plat *plat = dev_get_plat(dev); + + plat->regs = dev_read_addr_ptr(dev); + return 0; +} + +static const struct dm_gpio_ops ftgpio010_ops = { + .direction_input = ftgpio010_direction_input, + .direction_output = ftgpio010_direction_output, + .get_value = ftgpio010_get_value, + .set_value = ftgpio010_set_value, + .get_function = ftgpio010_get_function, +}; + +static const struct udevice_id ftgpio010_ids[] = { + { .compatible = "faraday,ftgpio010" }, + { } +}; + +U_BOOT_DRIVER(ftgpio010) = { + .name = "ftgpio010", + .id = UCLASS_GPIO, + .of_match = ftgpio010_ids, + .ops = &ftgpio010_ops, + .of_to_plat = ftgpio010_of_to_plat, + .plat_auto = sizeof(struct ftgpio010_plat), + .probe = ftgpio010_probe, +}; diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index b79e06290a..f674b0baa3 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -21,6 +21,7 @@ #include <net.h> #include <phy.h> #include <power-domain.h> +#include <soc.h> #include <linux/bitops.h> #include <linux/soc/ti/ti-udma.h> @@ -127,6 +128,8 @@ struct am65_cpsw_priv { bool has_phy; ofnode phy_node; u32 phy_addr; + + bool mdio_manual_mode; }; #ifdef PKTSIZE_ALIGN @@ -541,6 +544,20 @@ static const struct eth_ops am65_cpsw_ops = { .read_rom_hwaddr = am65_cpsw_read_rom_hwaddr, }; +static const struct soc_attr k3_mdio_soc_data[] = { + { .family = "AM62X", .revision = "SR1.0" }, + { .family = "AM64X", .revision = "SR1.0" }, + { .family = "AM64X", .revision = "SR2.0" }, + { .family = "AM65X", .revision = "SR1.0" }, + { .family = "AM65X", .revision = "SR2.0" }, + { .family = "J7200", .revision = "SR1.0" }, + { .family = "J7200", .revision = "SR2.0" }, + { .family = "J721E", .revision = "SR1.0" }, + { .family = "J721E", .revision = "SR1.1" }, + { .family = "J721S2", .revision = "SR1.0" }, + { /* sentinel */ }, +}; + static int am65_cpsw_mdio_init(struct udevice *dev) { struct am65_cpsw_priv *priv = dev_get_priv(dev); @@ -552,7 +569,8 @@ static int am65_cpsw_mdio_init(struct udevice *dev) cpsw_common->bus = cpsw_mdio_init(dev->name, cpsw_common->mdio_base, cpsw_common->bus_freq, - clk_get_rate(&cpsw_common->fclk)); + clk_get_rate(&cpsw_common->fclk), + priv->mdio_manual_mode); if (!cpsw_common->bus) return -EFAULT; @@ -657,6 +675,10 @@ static int am65_cpsw_port_probe(struct udevice *dev) sprintf(portname, "%s%s", dev->parent->name, dev->name); device_set_name(dev, portname); + priv->mdio_manual_mode = false; + if (soc_device_match(k3_mdio_soc_data)) + priv->mdio_manual_mode = true; + ret = am65_cpsw_ofdata_parse_phy(dev); if (ret) goto out; diff --git a/drivers/net/ti/cpsw.c b/drivers/net/ti/cpsw.c index 8988c21e66..41cba7930d 100644 --- a/drivers/net/ti/cpsw.c +++ b/drivers/net/ti/cpsw.c @@ -922,7 +922,8 @@ int _cpsw_register(struct cpsw_priv *priv) idx = idx + 1; } - priv->bus = cpsw_mdio_init(priv->dev->name, data->mdio_base, 0, 0); + priv->bus = cpsw_mdio_init(priv->dev->name, data->mdio_base, 0, 0, + false); if (!priv->bus) return -EFAULT; diff --git a/drivers/net/ti/cpsw_mdio.c b/drivers/net/ti/cpsw_mdio.c index f4cb86d10a..a5ba73b739 100644 --- a/drivers/net/ti/cpsw_mdio.c +++ b/drivers/net/ti/cpsw_mdio.c @@ -23,6 +23,11 @@ struct cpsw_mdio_regs { #define CONTROL_FAULT_ENABLE BIT(18) #define CONTROL_DIV_MASK GENMASK(15, 0) +#define MDIO_MAN_MDCLK_O BIT(2) +#define MDIO_MAN_OE BIT(1) +#define MDIO_MAN_PIN BIT(0) +#define MDIO_MANUALMODE BIT(31) + u32 alive; u32 link; u32 linkintraw; @@ -32,7 +37,9 @@ struct cpsw_mdio_regs { u32 userintmasked; u32 userintmaskset; u32 userintmaskclr; - u32 __reserved_1[20]; + u32 manualif; + u32 poll; + u32 __reserved_1[18]; struct { u32 access; @@ -51,6 +58,13 @@ struct cpsw_mdio_regs { #define PHY_REG_MASK 0x1f #define PHY_ID_MASK 0x1f +#define MDIO_BITRANGE 0x8000 +#define C22_READ_PATTERN 0x6 +#define C22_WRITE_PATTERN 0x5 +#define C22_BITRANGE 0x8 +#define PHY_BITRANGE 0x10 +#define PHY_DATA_BITRANGE 0x8000 + /* * This timeout definition is a worst-case ultra defensive measure against * unexpected controller lock ups. Ideally, we should never ever hit this @@ -58,12 +72,239 @@ struct cpsw_mdio_regs { */ #define CPSW_MDIO_TIMEOUT 100 /* msecs */ +enum cpsw_mdio_manual { + MDIO_PIN = 0, + MDIO_OE, + MDIO_MDCLK, +}; + struct cpsw_mdio { struct cpsw_mdio_regs *regs; struct mii_dev *bus; int div; }; +static void cpsw_mdio_disable(struct cpsw_mdio *mdio) +{ + u32 reg; + /* Disable MDIO state machine */ + reg = readl(&mdio->regs->control); + reg &= ~CONTROL_ENABLE; + + writel(reg, &mdio->regs->control); +} + +static void cpsw_mdio_enable_manual_mode(struct cpsw_mdio *mdio) +{ + u32 reg; + + /* set manual mode */ + reg = readl(&mdio->regs->poll); + reg |= MDIO_MANUALMODE; + + writel(reg, &mdio->regs->poll); +} + +static void cpsw_mdio_sw_set_bit(struct cpsw_mdio *mdio, + enum cpsw_mdio_manual bit) +{ + u32 reg; + + reg = readl(&mdio->regs->manualif); + + switch (bit) { + case MDIO_OE: + reg |= MDIO_MAN_OE; + writel(reg, &mdio->regs->manualif); + break; + case MDIO_PIN: + reg |= MDIO_MAN_PIN; + writel(reg, &mdio->regs->manualif); + break; + case MDIO_MDCLK: + reg |= MDIO_MAN_MDCLK_O; + writel(reg, &mdio->regs->manualif); + break; + default: + break; + }; +} + +static void cpsw_mdio_sw_clr_bit(struct cpsw_mdio *mdio, + enum cpsw_mdio_manual bit) +{ + u32 reg; + + reg = readl(&mdio->regs->manualif); + + switch (bit) { + case MDIO_OE: + reg &= ~MDIO_MAN_OE; + writel(reg, &mdio->regs->manualif); + break; + case MDIO_PIN: + reg &= ~MDIO_MAN_PIN; + writel(reg, &mdio->regs->manualif); + break; + case MDIO_MDCLK: + reg = readl(&mdio->regs->manualif); + reg &= ~MDIO_MAN_MDCLK_O; + writel(reg, &mdio->regs->manualif); + break; + default: + break; + }; +} + +static int cpsw_mdio_test_man_bit(struct cpsw_mdio *mdio, + enum cpsw_mdio_manual bit) +{ + u32 reg; + + reg = readl(&mdio->regs->manualif); + return test_bit(bit, ®); +} + +static void cpsw_mdio_toggle_man_bit(struct cpsw_mdio *mdio, + enum cpsw_mdio_manual bit) +{ + cpsw_mdio_sw_clr_bit(mdio, bit); + cpsw_mdio_sw_set_bit(mdio, bit); +} + +static void cpsw_mdio_man_send_pattern(struct cpsw_mdio *mdio, + u32 bitrange, u32 val) +{ + u32 i; + + for (i = bitrange; i; i = i >> 1) { + if (i & val) + cpsw_mdio_sw_set_bit(mdio, MDIO_PIN); + else + cpsw_mdio_sw_clr_bit(mdio, MDIO_PIN); + + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + } +} + +static void cpsw_mdio_sw_preamble(struct cpsw_mdio *mdio) +{ + u32 i; + + cpsw_mdio_sw_clr_bit(mdio, MDIO_OE); + + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_set_bit(mdio, MDIO_MDCLK); + + for (i = 0; i < 32; i++) { + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + } +} + +static int cpsw_mdio_sw_read(struct mii_dev *bus, int phy_id, + int dev_addr, int phy_reg) +{ + struct cpsw_mdio *mdio = bus->priv; + u32 reg, i; + u8 ack; + + if (phy_reg & ~PHY_REG_MASK || phy_id & ~PHY_ID_MASK) + return -EINVAL; + + cpsw_mdio_disable(mdio); + cpsw_mdio_enable_manual_mode(mdio); + cpsw_mdio_sw_preamble(mdio); + + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_set_bit(mdio, MDIO_OE); + + /* Issue clause 22 MII read function {0,1,1,0} */ + cpsw_mdio_man_send_pattern(mdio, C22_BITRANGE, C22_READ_PATTERN); + + /* Send the device number MSB first */ + cpsw_mdio_man_send_pattern(mdio, PHY_BITRANGE, phy_id); + + /* Send the register number MSB first */ + cpsw_mdio_man_send_pattern(mdio, PHY_BITRANGE, phy_reg); + + /* Send turn around cycles */ + cpsw_mdio_sw_clr_bit(mdio, MDIO_OE); + + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + ack = cpsw_mdio_test_man_bit(mdio, MDIO_PIN); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + reg = 0; + if (ack == 0) { + for (i = MDIO_BITRANGE; i; i = i >> 1) { + if (cpsw_mdio_test_man_bit(mdio, MDIO_PIN)) + reg |= i; + + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + } + } else { + for (i = MDIO_BITRANGE; i; i = i >> 1) + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + reg = 0xFFFF; + } + + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_set_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_set_bit(mdio, MDIO_MDCLK); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + return reg; +} + +static int cpsw_mdio_sw_write(struct mii_dev *bus, int phy_id, + int dev_addr, int phy_reg, u16 phy_data) +{ + struct cpsw_mdio *mdio = bus->priv; + + if ((phy_reg & ~PHY_REG_MASK) || (phy_id & ~PHY_ID_MASK)) + return -EINVAL; + + cpsw_mdio_disable(mdio); + cpsw_mdio_enable_manual_mode(mdio); + cpsw_mdio_sw_preamble(mdio); + + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_set_bit(mdio, MDIO_OE); + + /* Issue clause 22 MII write function {0,1,0,1} */ + cpsw_mdio_man_send_pattern(mdio, C22_BITRANGE, C22_WRITE_PATTERN); + + /* Send the device number MSB first */ + cpsw_mdio_man_send_pattern(mdio, PHY_BITRANGE, phy_id); + + /* Send the register number MSB first */ + cpsw_mdio_man_send_pattern(mdio, PHY_BITRANGE, phy_reg); + + /* set turn-around cycles */ + cpsw_mdio_sw_set_bit(mdio, MDIO_PIN); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_PIN); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + /* Send Register data MSB first */ + cpsw_mdio_man_send_pattern(mdio, PHY_DATA_BITRANGE, phy_data); + cpsw_mdio_sw_clr_bit(mdio, MDIO_OE); + + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_sw_clr_bit(mdio, MDIO_MDCLK); + cpsw_mdio_toggle_man_bit(mdio, MDIO_MDCLK); + + return 0; +} + /* wait until hardware is ready for another user access */ static int cpsw_mdio_wait_for_user_access(struct cpsw_mdio *mdio) { @@ -130,7 +371,7 @@ u32 cpsw_mdio_get_alive(struct mii_dev *bus) } struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, - u32 bus_freq, int fck_freq) + u32 bus_freq, int fck_freq, bool manual_mode) { struct cpsw_mdio *cpsw_mdio; int ret; @@ -172,8 +413,14 @@ struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, */ mdelay(1); - cpsw_mdio->bus->read = cpsw_mdio_read; - cpsw_mdio->bus->write = cpsw_mdio_write; + if (manual_mode) { + cpsw_mdio->bus->read = cpsw_mdio_sw_read; + cpsw_mdio->bus->write = cpsw_mdio_sw_write; + } else { + cpsw_mdio->bus->read = cpsw_mdio_read; + cpsw_mdio->bus->write = cpsw_mdio_write; + } + cpsw_mdio->bus->priv = cpsw_mdio; snprintf(cpsw_mdio->bus->name, sizeof(cpsw_mdio->bus->name), name); diff --git a/drivers/net/ti/cpsw_mdio.h b/drivers/net/ti/cpsw_mdio.h index dbf4a2dcac..9b98763656 100644 --- a/drivers/net/ti/cpsw_mdio.h +++ b/drivers/net/ti/cpsw_mdio.h @@ -11,7 +11,7 @@ struct cpsw_mdio; struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, - u32 bus_freq, int fck_freq); + u32 bus_freq, int fck_freq, bool manual_mode); void cpsw_mdio_free(struct mii_dev *bus); u32 cpsw_mdio_get_alive(struct mii_dev *bus); diff --git a/drivers/net/ti/keystone_net.c b/drivers/net/ti/keystone_net.c index fbec69f571..1bdbd599d7 100644 --- a/drivers/net/ti/keystone_net.c +++ b/drivers/net/ti/keystone_net.c @@ -571,7 +571,8 @@ static int ks2_eth_probe(struct udevice *dev) mdio_bus = cpsw_mdio_init("ethernet-mdio", priv->mdio_base, EMAC_MDIO_CLOCK_FREQ, - EMAC_MDIO_BUS_FREQ); + EMAC_MDIO_BUS_FREQ, + false); if (!mdio_bus) { pr_err("MDIO alloc failed\n"); return -ENOMEM; |