Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2018 * Mario Six, Guntermann & Drunck GmbH, mario.six@gdsys.cc * * base on the MPC83xx serdes initialization, which is * * Copyright 2007,2011 Freescale Semiconductor, Inc. * Copyright (C) 2008 MontaVista Software, Inc. */ #include <dm.h> #include <log.h> #include <mapmem.h> #include <misc.h> #include <linux/delay.h> #include "mpc83xx_serdes.h" /** * struct mpc83xx_serdes_priv - Private structure for MPC83xx serdes * @regs: The device's register map * @rfcks: Variable to keep the serdes reference clock selection set during * initialization in (is or'd to every value written to SRDSCR4) */ struct mpc83xx_serdes_priv { struct mpc83xx_serdes_regs *regs; u32 rfcks; }; /** * setup_sata() - Configure the SerDes device to SATA mode * @dev: The device to configure */ static 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); } /** * setup_pex() - Configure the SerDes device to PCI Express mode * @dev: The device to configure * @type: The PCI Express type to configure for (x1 or x2) */ static 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); } /** * setup_sgmii() - Configure the SerDes device to SGMII mode * @dev: The device to configure */ static 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); } static 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)); switch (dev_read_u32_default(dev, "serdes-clk", -1)) { case 100: priv->rfcks = SRDSCR4_RFCKS_100; break; case 125: priv->rfcks = SRDSCR4_RFCKS_125; break; case 150: priv->rfcks = SRDSCR4_RFCKS_150; break; default: debug("%s: Could not read serdes clock value\n", dev->name); return -EINVAL; } vdd = dev_read_bool(dev, "vdd"); /* 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 { debug("%s: Invalid protocol value %s\n", dev->name, proto); 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, .of_match = mpc83xx_serdes_ids, .probe = mpc83xx_serdes_probe, .priv_auto = sizeof(struct mpc83xx_serdes_priv), }; |