aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/nuvoton/Makefile1
-rw-r--r--drivers/clk/nuvoton/clk_npcm8xx.c98
-rw-r--r--drivers/dma/ti/k3-udma.c1
-rw-r--r--drivers/gpio/Kconfig6
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/ftgpio010.c111
-rw-r--r--drivers/net/ti/am65-cpsw-nuss.c24
-rw-r--r--drivers/net/ti/cpsw.c3
-rw-r--r--drivers/net/ti/cpsw_mdio.c255
-rw-r--r--drivers/net/ti/cpsw_mdio.h2
-rw-r--r--drivers/net/ti/keystone_net.c3
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(&regs->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 ? &regs->set : &regs->clear, 1 << pin);
+ setbits_le32(&regs->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(&regs->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 ? &regs->set : &regs->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(&regs->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, &reg);
+}
+
+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;