The SerDes(serializer/deserializer) PHY block is a new SoC block used
in Freescale chips to support multiple serial interfaces, such as PCI
Express, SGMII, SATA.

Signed-off-by: Li Yang <[EMAIL PROTECTED]>
---
 arch/powerpc/platforms/Kconfig   |    7 ++
 arch/powerpc/sysdev/Makefile     |    1 +
 arch/powerpc/sysdev/fsl_serdes.c |  195 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 203 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/sysdev/fsl_serdes.c

diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 229d355..5d64f84 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -315,6 +315,13 @@ config FSL_ULI1575
 config CPM
        bool
 
+config FSL_SERDES
+       bool
+       help
+         The SerDes(serializer/deserializer) PHY block is a new SoC block
+         used in Freescale chips to support multiple serial interfaces,
+         such as PCI Express, SGMII, SATA.
+
 source "arch/powerpc/sysdev/bestcomm/Kconfig"
 
 endmenu
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index 99a77d7..2343ea4 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_MV64X60)         += $(mv64x60-y) mv64x60_pic.o 
mv64x60_dev.o \
                                   mv64x60_udbg.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc_cmos_setup.o
 obj-$(CONFIG_AXON_RAM)         += axonram.o
+obj-$(CONFIG_FSL_SERDES)       += fsl_serdes.o
 
 ifeq ($(CONFIG_PPC_MERGE),y)
 obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o
diff --git a/arch/powerpc/sysdev/fsl_serdes.c b/arch/powerpc/sysdev/fsl_serdes.c
new file mode 100644
index 0000000..670015d
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_serdes.c
@@ -0,0 +1,195 @@
+/*
+ * arch/powerpc/sysdev/fsl_serdes.c
+ *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <[EMAIL PROTECTED]>
+ *
+ * Freescale SerDes initialization routines
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+
+#define FSL_SRDSCR0_OFFS               0x0
+#define FSL_SRDSCR0_DPP_1V2            0x00008800
+#define FSL_SRDSCR1_OFFS               0x4
+#define FSL_SRDSCR1_PLLBW              0x00000040
+#define FSL_SRDSCR2_OFFS               0x8
+#define FSL_SRDSCR2_VDD_1V2            0x00800000
+#define FSL_SRDSCR2_SEIC_MASK          0x00001c1c
+#define FSL_SRDSCR2_SEIC_SATA          0x00001414
+#define FSL_SRDSCR2_SEIC_PEX           0x00001010
+#define FSL_SRDSCR2_SEIC_SGMII         0x00000101
+#define FSL_SRDSCR3_OFFS               0xc
+#define FSL_SRDSCR3_KFR_SATA           0x10100000
+#define FSL_SRDSCR3_KPH_SATA           0x04040000
+#define FSL_SRDSCR3_SDFM_SATA_PEX      0x01010000
+#define FSL_SRDSCR3_SDTXL_SATA         0x00000505
+#define FSL_SRDSCR4_OFFS               0x10
+#define FSL_SRDSCR4_PROT_SATA          0x00000808
+#define FSL_SRDSCR4_PROT_PEX           0x00000101
+#define FSL_SRDSCR4_PROT_SGMII         0x00000505
+#define FSL_SRDSCR4_PLANE_X2           0x01000000
+#define FSL_SRDSCR4_RFCKS_100          0x00000000
+#define FSL_SRDSCR4_RFCKS_125          0x10000000
+#define FSL_SRDSCR4_RFCKS_150          0x30000000
+#define FSL_SRDSRSTCTL_OFFS            0x20
+#define FSL_SRDSRSTCTL_RST             0x80000000
+#define FSL_SRDSRSTCTL_SATA_RESET      0xf
+
+static int fsl_serdes_probe(struct of_device *ofdev,
+               const struct of_device_id *match)
+{
+       struct device_node *np = ofdev->node;
+       void __iomem *regs;
+       const char *prot;
+       const unsigned int *freq;
+       u32 rfcks;
+
+       regs = of_iomap(np, 0);
+       if (!regs)
+               return -ENOMEM;
+
+       prot = of_get_property(np, "protocol", NULL);
+       if (!prot)
+               goto out;
+       freq = of_get_property(np, "clock", NULL);
+       if (!freq)
+               goto out;
+       switch (*freq) {
+       case 100:
+               rfcks = FSL_SRDSCR4_RFCKS_100;
+               break;
+       case 125:
+               rfcks = FSL_SRDSCR4_RFCKS_125;
+               break;
+       case 150:
+               rfcks = FSL_SRDSCR4_RFCKS_150;
+               break;
+       default:
+               printk(KERN_ERR "SerDes: Wrong frequency\n");
+               goto out;
+       }
+
+       /* Use default prescale and counter */
+
+       /* 1.0V corevdd */
+       if (of_get_property(np, "vdd-1v", NULL)) {
+               /* DPPE/DPPA = 0 */
+               clrbits32(regs + FSL_SRDSCR0_OFFS, FSL_SRDSCR0_DPP_1V2);
+
+               /* VDD = 0 */
+               clrbits32(regs + FSL_SRDSCR2_OFFS, FSL_SRDSCR2_VDD_1V2);
+       }
+
+       /* protocol specific configuration */
+       if (!strcmp(prot, "sata")) {
+               /* Set and clear reset bits */
+               setbits32(regs + FSL_SRDSRSTCTL_OFFS,
+                               FSL_SRDSRSTCTL_SATA_RESET);
+               mdelay(1);
+               clrbits32(regs + FSL_SRDSRSTCTL_OFFS,
+                               FSL_SRDSRSTCTL_SATA_RESET);
+
+               /* Configure SRDSCR1 */
+               clrbits32(regs + FSL_SRDSCR1_OFFS, FSL_SRDSCR1_PLLBW);
+
+               /* Configure SRDSCR2 */
+               clrsetbits_be32(regs + FSL_SRDSCR2_OFFS,
+                               FSL_SRDSCR2_SEIC_MASK, FSL_SRDSCR2_SEIC_SATA);
+
+               /* Configure SRDSCR3 */
+               out_be32(regs + FSL_SRDSCR3_OFFS, FSL_SRDSCR3_KFR_SATA |
+                               FSL_SRDSCR3_KPH_SATA |
+                               FSL_SRDSCR3_SDFM_SATA_PEX |
+                               FSL_SRDSCR3_SDTXL_SATA);
+
+               /* Configure SRDSCR4 */
+               out_be32(regs + FSL_SRDSCR4_OFFS, rfcks |
+                               FSL_SRDSCR4_PROT_SATA);
+
+       } else if (!strcmp(prot, "pcie")) {
+               /* Configure SRDSCR1 */
+               setbits32(regs + FSL_SRDSCR1_OFFS, FSL_SRDSCR1_PLLBW);
+
+               /* Configure SRDSCR2 */
+               clrsetbits_be32(regs + FSL_SRDSCR2_OFFS, FSL_SRDSCR2_SEIC_MASK,
+                               FSL_SRDSCR2_SEIC_PEX);
+
+               /* Configure SRDSCR3 */
+               out_be32(regs + FSL_SRDSCR3_OFFS, FSL_SRDSCR3_SDFM_SATA_PEX);
+
+               /* Configure SRDSCR4 */
+               if (of_get_property(np, "pcie-x2", NULL))
+                       out_be32(regs + FSL_SRDSCR4_OFFS, rfcks |
+                               FSL_SRDSCR4_PROT_PEX | FSL_SRDSCR4_PLANE_X2);
+               else
+                       out_be32(regs + FSL_SRDSCR4_OFFS, rfcks |
+                               FSL_SRDSCR4_PROT_PEX);
+
+       } else if (!strcmp(prot, "sgmii")) {
+               /* Configure SRDSCR1 */
+               clrbits32(regs + FSL_SRDSCR1_OFFS, FSL_SRDSCR1_PLLBW);
+
+               /* Configure SRDSCR2 */
+               clrsetbits_be32(regs + FSL_SRDSCR2_OFFS, FSL_SRDSCR2_SEIC_MASK,
+                               FSL_SRDSCR2_SEIC_SGMII);
+
+               /* Configure SRDSCR3 */
+               out_be32(regs + FSL_SRDSCR3_OFFS, 0);
+
+               /* Configure SRDSCR4 */
+               out_be32(regs + FSL_SRDSCR4_OFFS, rfcks |
+                               FSL_SRDSCR4_PROT_SGMII);
+
+       } else {
+               printk(KERN_ERR "SerDes: Wrong protocol\n");
+               goto out;
+       }
+
+       /* Do a software reset */
+       setbits32(regs + FSL_SRDSRSTCTL_OFFS, FSL_SRDSRSTCTL_RST);
+       iounmap(regs);
+
+       dev_printk(KERN_INFO, &ofdev->dev, "Initialized as %s\n", prot);
+
+       return 0;
+out:
+       iounmap(regs);
+       return -EINVAL;
+}
+
+static struct of_device_id fsl_serdes_match[] = {
+       {
+               .compatible = "fsl,serdes",
+       },
+       {},
+};
+
+static struct of_platform_driver fsl_serdes_driver = {
+       .name           = "fsl-serdes",
+       .match_table    = fsl_serdes_match,
+       .probe          = fsl_serdes_probe,
+};
+
+static int __init fsl_serdes_init(void)
+{
+       of_register_platform_driver(&fsl_serdes_driver);
+       return 0;
+}
+device_initcall(fsl_serdes_init);
-- 
1.5.3.2.104.g41ef

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to