Add a driver to configure the SerDes (Serializer/Deserializer) lanes on the MPC83xx architecture.
Signed-off-by: Mario Six <mario....@gdsys.cc> --- v2 -> v3: * Added driver file to MAINTAINERS v1 -> v2: No changes --- MAINTAINERS | 1 + arch/powerpc/cpu/mpc83xx/serdes.c | 4 + arch/powerpc/include/asm/fsl_mpc83xx_serdes.h | 4 + drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/mpc83xx_serdes.c | 228 ++++++++++++++++++++++++++ 6 files changed, 245 insertions(+) create mode 100644 drivers/misc/mpc83xx_serdes.c diff --git a/MAINTAINERS b/MAINTAINERS index 11965be1402..d55632617ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -477,6 +477,7 @@ F: include/dt-bindings/clk/mpc83xx-clk.h F: drivers/timer/mpc83xx_timer.c F: drivers/cpu/mpc83xx_cpu.c F: drivers/cpu/mpc83xx_cpu.h +F: drivers/misc/mpc83xx_serdes.c F: arch/powerpc/cpu/mpc83xx/ F: arch/powerpc/include/asm/arch-mpc83xx/ diff --git a/arch/powerpc/cpu/mpc83xx/serdes.c b/arch/powerpc/cpu/mpc83xx/serdes.c index 982a4475f00..8242f952653 100644 --- a/arch/powerpc/cpu/mpc83xx/serdes.c +++ b/arch/powerpc/cpu/mpc83xx/serdes.c @@ -8,6 +8,8 @@ * Author: Li Yang <le...@freescale.com> */ +#ifndef CONFIG_MPC83XX_SERDES + #include <config.h> #include <common.h> #include <asm/io.h> @@ -148,3 +150,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 e51d060d6a7..a02b5992654 100644 --- a/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h +++ b/arch/powerpc/include/asm/fsl_mpc83xx_serdes.h @@ -6,6 +6,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) @@ -19,4 +21,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 be900cf4d6e..4794f615093 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -268,4 +268,11 @@ config GDSYS_RXAUI_CTRL depends on MISC help Support gdsys FPGA's RXAUI control. + +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 e362609d62a..f53f87a3639 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o obj-$(CONFIG_STM32_RCC) += stm32_rcc.o obj-$(CONFIG_SYS_DPAA_QBMAN) += fsl_portals.o obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.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 00000000000..981128e300d --- /dev/null +++ b/drivers/misc/mpc83xx_serdes.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (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. + */ + +#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.11.0 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot