Add a driver to configure the SerDes (Serializer/Deserializer) lanes on the MPC83xx architecture.
Signed-off-by: Mario Six <mario....@gdsys.cc> --- arch/powerpc/cpu/mpc83xx/serdes.c | 4 + arch/powerpc/include/asm/fsl_mpc83xx_serdes.h | 4 + drivers/misc/Kconfig | 5 + drivers/misc/Makefile | 1 + drivers/misc/mpc83xx_serdes.c | 229 ++++++++++++++++++++++++++ 5 files changed, 243 insertions(+) create mode 100644 drivers/misc/mpc83xx_serdes.c diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c index a0bc477dc3..67b9f152d1 100644 --- a/arch/powerpc/cpu/mpc83xx/serdes.c +++ b/arch/powerpc/cpu/mpc83xx/serdes.c @@ -9,6 +9,8 @@ * SPDX-License-Identifier: GPL-2.0+ */ +#ifndef CONFIG_MPC83XX_SERDES + #include <config.h> #include <common.h> #include <asm/io.h> @@ -149,3 +151,5 @@ void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd) tmp |= FSL_SRDSRSTCTL_RST; out_be32(regs + FSL_SRDSRSTCTL_OFFS, tmp); } + +#endif /* !CONFIG_MPC83XX_SERDES */ diff --git a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h index 5a06a09567..a66c878c1f 100644 --- a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h +++ b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h @@ -7,6 +7,8 @@ #ifndef __FSL_MPC83XX_SERDES_H #define __FSL_MPC83XX_SERDES_H +#ifndef CONFIG_MPC83XX_SERDES + #include <config.h> #define FSL_SERDES_CLK_100 (0 << 28) @@ -20,4 +22,6 @@ extern void fsl_setup_serdes(u32 offset, char proto, u32 rfcks, char vdd); +#endif /* !CONFIG_MPC83XX_SERDES */ + #endif /* __FSL_MPC83XX_SERDES_H */ diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d774569cbc..1afb003444 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -263,5 +263,10 @@ config SYS_I2C_EEPROM_ADDR_OVERFLOW endif +config MPC83XX_SERDES + bool "Enable MPC83xx serdes driver" + depends on MISC + help + Support for serdes found on MPC83xx SoCs. endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e8d598cd47..30bc30b9eb 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,3 +54,4 @@ obj-$(CONFIG_QFW) += qfw.o obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o +obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o diff --git a/drivers/misc/mpc83xx_serdes.c b/drivers/misc/mpc83xx_serdes.c new file mode 100644 index 0000000000..ea538dfd11 --- /dev/null +++ b/drivers/misc/mpc83xx_serdes.c @@ -0,0 +1,229 @@ +/* + * (C) Copyright 2018 + * Mario Six, Guntermann & Drunck GmbH, mario....@gdsys.cc + * + * base on the MPC83xx serdes initialization, which is + * + * Copyright 2007,2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 MontaVista Software, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <misc.h> +#include <mapmem.h> + +enum { + SRDSCR0_DPP_1V2 = 0x00008800, + + SRDSCR0_TXEQA_MASK = 0x00007000, + SRDSCR0_TXEQA_SATA = 0x00001000, + SRDSCR0_TXEQE_MASK = 0x00000700, + SRDSCR0_TXEQE_SATA = 0x00000100, +}; + +enum { + SRDSCR1_PLLBW = 0x00000040 +}; + +enum { + SRDSCR2_VDD_1V2 = 0x00800000, + + SRDSCR2_SEIC_MASK = 0x00001c1c, + SRDSCR2_SEIC_SATA = 0x00001414, + SRDSCR2_SEIC_PEX = 0x00001010, + SRDSCR2_SEIC_SGMII = 0x00000101, +}; + +enum { + SRDSCR3_KFR_SATA = 0x10100000, + SRDSCR3_KPH_SATA = 0x04040000, + SRDSCR3_SDFM_SATA_PEX = 0x01010000, + SRDSCR3_SDTXL_SATA = 0x00000505, +}; + +enum { + SRDSCR4_PROT_SATA = 0x00000808, + SRDSCR4_PROT_PEX = 0x00000101, + SRDSCR4_PROT_SGMII = 0x00000505, + + SRDSCR4_PLANE_X2 = 0x01000000, +}; + +enum { + SRDSRSTCTL_RST = 0x80000000, + SRDSRSTCTL_SATA_RESET = 0xf, +}; + +enum { + SERDES_CLK_100 = (0 << 28), + SERDES_CLK_125 = (1 << 28), + SERDES_CLK_150 = (3 << 28), +}; + +struct mpc83xx_serdes_regs { + u32 srdscr0; + u32 srdscr1; + u32 srdscr2; + u32 srdscr3; + u32 srdscr4; + u8 fill0[12]; + u32 srdsrstctl; +}; + +enum pex_type { + PEX_X1, + PEX_X2, +}; + +struct mpc83xx_serdes_priv { + struct mpc83xx_serdes_regs *regs; + u32 rfcks; +}; + +static const struct misc_ops mpc83xx_serdes_ops = { +}; + +void setup_sata(struct udevice *dev) +{ + struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); + + /* Set and clear reset bits */ + setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET); + udelay(1000); + clrbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_SATA_RESET); + + /* Configure SRDSCR0 */ + clrsetbits_be32(&priv->regs->srdscr0, + SRDSCR0_TXEQA_MASK | SRDSCR0_TXEQE_MASK, + SRDSCR0_TXEQA_SATA | SRDSCR0_TXEQE_SATA); + + /* Configure SRDSCR1 */ + clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); + + /* Configure SRDSCR2 */ + clrsetbits_be32(&priv->regs->srdscr2, + SRDSCR2_SEIC_MASK, + SRDSCR2_SEIC_SATA); + + /* Configure SRDSCR3 */ + out_be32(&priv->regs->srdscr3, + SRDSCR3_KFR_SATA | SRDSCR3_KPH_SATA | + SRDSCR3_SDFM_SATA_PEX | SRDSCR3_SDTXL_SATA); + + /* Configure SRDSCR4 */ + out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SATA); +} + +void setup_pex(struct udevice *dev, enum pex_type type) +{ + struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); + + /* Configure SRDSCR1 */ + setbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); + + /* Configure SRDSCR2 */ + clrsetbits_be32(&priv->regs->srdscr2, + SRDSCR2_SEIC_MASK, + SRDSCR2_SEIC_PEX); + + /* Configure SRDSCR3 */ + out_be32(&priv->regs->srdscr3, SRDSCR3_SDFM_SATA_PEX); + + /* Configure SRDSCR4 */ + if (type == PEX_X2) + out_be32(&priv->regs->srdscr4, + priv->rfcks | SRDSCR4_PROT_PEX | SRDSCR4_PLANE_X2); + else + out_be32(&priv->regs->srdscr4, + priv->rfcks | SRDSCR4_PROT_PEX); +} + +void setup_sgmii(struct udevice *dev) +{ + struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); + + /* Configure SRDSCR1 */ + clrbits_be32(&priv->regs->srdscr1, SRDSCR1_PLLBW); + + /* Configure SRDSCR2 */ + clrsetbits_be32(&priv->regs->srdscr2, + SRDSCR2_SEIC_MASK, + SRDSCR2_SEIC_SGMII); + + /* Configure SRDSCR3 */ + out_be32(&priv->regs->srdscr3, 0); + + /* Configure SRDSCR4 */ + out_be32(&priv->regs->srdscr4, priv->rfcks | SRDSCR4_PROT_SGMII); +} + +int mpc83xx_serdes_probe(struct udevice *dev) +{ + struct mpc83xx_serdes_priv *priv = dev_get_priv(dev); + bool vdd; + const char *proto; + + priv->regs = map_sysmem(dev_read_addr(dev), + sizeof(struct mpc83xx_serdes_regs)); + + vdd = dev_read_bool(dev, "vdd"); + + switch (dev_read_u32_default(dev, "serdes-clk", -1)) { + case 100: + priv->rfcks = SERDES_CLK_100; + break; + case 125: + priv->rfcks = SERDES_CLK_125; + break; + case 150: + priv->rfcks = SERDES_CLK_150; + break; + default: + return -EINVAL; + } + + /* 1.0V corevdd */ + if (vdd) { + /* DPPE/DPPA = 0 */ + clrbits_be32(&priv->regs->srdscr0, SRDSCR0_DPP_1V2); + + /* VDD = 0 */ + clrbits_be32(&priv->regs->srdscr0, SRDSCR2_VDD_1V2); + } + + proto = dev_read_string(dev, "proto"); + + /* protocol specific configuration */ + if (!strcmp(proto, "sata")) + setup_sata(dev); + else if (!strcmp(proto, "pex")) + setup_pex(dev, PEX_X1); + else if (!strcmp(proto, "pex-x2")) + setup_pex(dev, PEX_X2); + else if (!strcmp(proto, "sgmii")) + setup_sgmii(dev); + else + return -EINVAL; + + /* Do a software reset */ + setbits_be32(&priv->regs->srdsrstctl, SRDSRSTCTL_RST); + + return 0; +} + +static const struct udevice_id mpc83xx_serdes_ids[] = { + { .compatible = "fsl,mpc83xx-serdes" }, + { } +}; + +U_BOOT_DRIVER(mpc83xx_serdes) = { + .name = "mpc83xx_serdes", + .id = UCLASS_MISC, + .ops = &mpc83xx_serdes_ops, + .of_match = mpc83xx_serdes_ids, + .probe = mpc83xx_serdes_probe, + .priv_auto_alloc_size = sizeof(struct mpc83xx_serdes_priv), +}; -- 2.16.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot