diff options
author | Tom Rini <trini@konsulko.com> | 2016-05-20 20:43:27 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2016-05-23 11:51:37 -0400 |
commit | d7d000311285e4b8d11e089ca13ea456a01be3b8 (patch) | |
tree | d156930b1f4ebf864dd42ec6e43e24045d975c55 /arch/mips/mach-ath79/reset.c | |
parent | d38fca40c84e6d5f73dfe43cef4c46d42f90aa66 (diff) | |
parent | 40ba13c98627055465709acd67872e381b42f928 (diff) |
Merge branch 'master' of git://git.denx.de/u-boot-mips
Diffstat (limited to 'arch/mips/mach-ath79/reset.c')
-rw-r--r-- | arch/mips/mach-ath79/reset.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c new file mode 100644 index 0000000000..188eccb9bf --- /dev/null +++ b/arch/mips/mach-ath79/reset.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/addrspace.h> +#include <asm/types.h> +#include <mach/ath79.h> +#include <mach/ar71xx_regs.h> + +void _machine_restart(void) +{ + void __iomem *base; + u32 reg = 0; + + base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, + MAP_NOCACHE); + if (soc_is_ar71xx()) + reg = AR71XX_RESET_REG_RESET_MODULE; + else if (soc_is_ar724x()) + reg = AR724X_RESET_REG_RESET_MODULE; + else if (soc_is_ar913x()) + reg = AR913X_RESET_REG_RESET_MODULE; + else if (soc_is_ar933x()) + reg = AR933X_RESET_REG_RESET_MODULE; + else if (soc_is_ar934x()) + reg = AR934X_RESET_REG_RESET_MODULE; + else if (soc_is_qca953x()) + reg = QCA953X_RESET_REG_RESET_MODULE; + else if (soc_is_qca955x()) + reg = QCA955X_RESET_REG_RESET_MODULE; + else if (soc_is_qca956x()) + reg = QCA956X_RESET_REG_RESET_MODULE; + else + puts("Reset register not defined for this SOC\n"); + + if (reg) + setbits_be32(base + reg, AR71XX_RESET_FULL_CHIP); + + while (1) + /* NOP */; +} + +u32 get_bootstrap(void) +{ + void __iomem *base; + u32 reg = 0; + + base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, + MAP_NOCACHE); + if (soc_is_ar933x()) + reg = AR933X_RESET_REG_BOOTSTRAP; + else if (soc_is_ar934x()) + reg = AR934X_RESET_REG_BOOTSTRAP; + else if (soc_is_qca953x()) + reg = QCA953X_RESET_REG_BOOTSTRAP; + else if (soc_is_qca955x()) + reg = QCA955X_RESET_REG_BOOTSTRAP; + else if (soc_is_qca956x()) + reg = QCA956X_RESET_REG_BOOTSTRAP; + else + puts("Bootstrap register not defined for this SOC\n"); + + if (reg) + return readl(base + reg); + + return 0; +} + +static int eth_init_ar933x(void) +{ + void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, + MAP_NOCACHE); + void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, + MAP_NOCACHE); + void __iomem *gregs = map_physmem(AR933X_GMAC_BASE, AR933X_GMAC_SIZE, + MAP_NOCACHE); + const u32 mask = AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO | + AR933X_RESET_GE1_MAC | AR933X_RESET_GE1_MDIO | + AR933X_RESET_ETH_SWITCH; + + /* Clear MDIO slave EN bit. */ + clrbits_be32(rregs + AR933X_RESET_REG_BOOTSTRAP, BIT(17)); + mdelay(10); + + /* Get Atheros S26 PHY out of reset. */ + clrsetbits_be32(pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG, + 0x1f, 0x10); + mdelay(10); + + setbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask); + mdelay(10); + clrbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask); + mdelay(10); + + /* Configure AR93xx GMAC register. */ + clrsetbits_be32(gregs + AR933X_GMAC_REG_ETH_CFG, + AR933X_ETH_CFG_MII_GE0_MASTER | + AR933X_ETH_CFG_MII_GE0_SLAVE, + AR933X_ETH_CFG_MII_GE0_SLAVE); + return 0; +} + +static int eth_init_ar934x(void) +{ + void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE, + MAP_NOCACHE); + void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE, + MAP_NOCACHE); + void __iomem *gregs = map_physmem(AR934X_GMAC_BASE, AR934X_GMAC_SIZE, + MAP_NOCACHE); + const u32 mask = AR934X_RESET_GE0_MAC | AR934X_RESET_GE0_MDIO | + AR934X_RESET_GE1_MAC | AR934X_RESET_GE1_MDIO | + AR934X_RESET_ETH_SWITCH_ANALOG; + u32 reg; + + reg = readl(rregs + AR934X_RESET_REG_BOOTSTRAP); + if (reg & AR934X_BOOTSTRAP_REF_CLK_40) + writel(0x570, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG); + else + writel(0x271, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG); + writel(BIT(26) | BIT(25), pregs + AR934X_PLL_ETH_XMII_CONTROL_REG); + + setbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask); + mdelay(1); + clrbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask); + mdelay(1); + + /* Configure AR934x GMAC register. */ + writel(AR934X_ETH_CFG_RGMII_GMAC0, gregs + AR934X_GMAC_REG_ETH_CFG); + return 0; +} + +int ath79_eth_reset(void) +{ + /* + * Un-reset ethernet. DM still doesn't have any notion of reset + * framework, so we do it by hand here. + */ + if (soc_is_ar933x()) + return eth_init_ar933x(); + if (soc_is_ar934x()) + return eth_init_ar934x(); + + return -EINVAL; +} + +static int usb_reset_ar933x(void __iomem *reset_regs) +{ + /* Ungate the USB block */ + setbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, + AR933X_RESET_USBSUS_OVERRIDE); + mdelay(1); + clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, + AR933X_RESET_USB_HOST); + mdelay(1); + clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE, + AR933X_RESET_USB_PHY); + mdelay(1); + + return 0; +} + +static int usb_reset_ar934x(void __iomem *reset_regs) +{ + /* Ungate the USB block */ + setbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, + AR934X_RESET_USBSUS_OVERRIDE); + mdelay(1); + clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, + AR934X_RESET_USB_PHY); + mdelay(1); + clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, + AR934X_RESET_USB_PHY_ANALOG); + mdelay(1); + clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE, + AR934X_RESET_USB_HOST); + mdelay(1); + + return 0; +} + +int ath79_usb_reset(void) +{ + void __iomem *usbc_regs = map_physmem(AR71XX_USB_CTRL_BASE, + AR71XX_USB_CTRL_SIZE, + MAP_NOCACHE); + void __iomem *reset_regs = map_physmem(AR71XX_RESET_BASE, + AR71XX_RESET_SIZE, + MAP_NOCACHE); + /* + * Turn on the Buff and Desc swap bits. + * NOTE: This write into an undocumented register in mandatory to + * get the USB controller operational in BigEndian mode. + */ + writel(0xf0000, usbc_regs + AR71XX_USB_CTRL_REG_CONFIG); + + if (soc_is_ar933x()) + return usb_reset_ar933x(reset_regs); + if (soc_is_ar934x()) + return usb_reset_ar934x(reset_regs); + + return -EINVAL; +} |