From 99ac99c4c6134cc12abee1f845a897eafb125ba3 Mon Sep 17 00:00:00 2001 From: Shubhrajyoti Datta Date: Mon, 31 Aug 2015 16:36:13 +0530 Subject: [PATCH] misc: jesd204b driver support Update the jesd driver for line rate change. Add support for jesd phy. Signed-off-by: Shubhrajyoti Datta Signed-off-by: Michal Simek State: pending --- drivers/misc/jesd204b/Kconfig | 12 + drivers/misc/jesd204b/Makefile | 3 + drivers/misc/jesd204b/gtx7s_cpll_bands.c | 88 ++++++ drivers/misc/jesd204b/gtx7s_cpll_bands.h | 31 ++ drivers/misc/jesd204b/gtx7s_qpll_bands.c | 96 ++++++ drivers/misc/jesd204b/gtx7s_qpll_bands.h | 30 ++ drivers/misc/jesd204b/jesd_phy.c | 384 +++++++++++++++++++++++ drivers/misc/jesd204b/jesd_phy.h | 42 +++ drivers/misc/jesd204b/s7_gtxe2_drp.h | 123 ++++++++ drivers/misc/jesd204b/xilinx_jesd204b.c | 61 +--- 10 files changed, 823 insertions(+), 47 deletions(-) create mode 100644 drivers/misc/jesd204b/gtx7s_cpll_bands.c create mode 100644 drivers/misc/jesd204b/gtx7s_cpll_bands.h create mode 100644 drivers/misc/jesd204b/gtx7s_qpll_bands.c create mode 100644 drivers/misc/jesd204b/gtx7s_qpll_bands.h create mode 100644 drivers/misc/jesd204b/jesd_phy.c create mode 100644 drivers/misc/jesd204b/jesd_phy.h create mode 100644 drivers/misc/jesd204b/s7_gtxe2_drp.h diff --git a/drivers/misc/jesd204b/Kconfig b/drivers/misc/jesd204b/Kconfig index ce67b210723866..aff08cfe8f8236 100644 --- a/drivers/misc/jesd204b/Kconfig +++ b/drivers/misc/jesd204b/Kconfig @@ -14,3 +14,15 @@ config XILINX_JESD204B To compile this driver as a module, choose M here: the module will be called jesd204b. + +config XILINX_JESD204B_PHY + tristate "JESD Phy Driver" + depends on XILINX_JESD204B + help + This is JESD204b Phy Interface. It enables support for xilinx jesd204b phy + controller. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called jesd204b_phy. diff --git a/drivers/misc/jesd204b/Makefile b/drivers/misc/jesd204b/Makefile index 0348e0889f222f..7723fcb002c231 100644 --- a/drivers/misc/jesd204b/Makefile +++ b/drivers/misc/jesd204b/Makefile @@ -1,2 +1,5 @@ +obj-$(CONFIG_XILINX_JESD204B_PHY) += jesd204b_phy.o +jesd204b_phy-y += jesd_phy.o gtx7s_cpll_bands.o \ + gtx7s_qpll_bands.o obj-$(CONFIG_XILINX_JESD204B) += jesd204b.o jesd204b-y += xilinx_jesd204b.o diff --git a/drivers/misc/jesd204b/gtx7s_cpll_bands.c b/drivers/misc/jesd204b/gtx7s_cpll_bands.c new file mode 100644 index 00000000000000..a9610f7ade6711 --- /dev/null +++ b/drivers/misc/jesd204b/gtx7s_cpll_bands.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "s7_gtxe2_drp.h" +#include "gtx7s_cpll_bands.h" + +static const u32 gtx7s_cpll_channel_address_lut + [GTX7S_CPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_ADDR, + RXCDR_CFG1_ADDR, + RXCDR_CFG2_ADDR, + RXCDR_CFG3_ADDR, + RXCDR_CFG4_ADDR, + RXOUT_DIV_ADDR, + TXOUT_DIV_ADDR, + RX_DFE_LPM_CFG_ADDR +}; + +static const u32 gtx7s_cpll_channel_offset_lut + [GTX7S_CPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_OFFSET, + RXCDR_CFG1_OFFSET, + RXCDR_CFG2_OFFSET, + RXCDR_CFG3_OFFSET, + RXCDR_CFG4_OFFSET, + RXOUT_DIV_OFFSET, + TXOUT_DIV_OFFSET, + RX_DFE_LPM_CFG_OFFSET +}; + +static const u32 gtx7s_cpll_channel_mask_lut + [GTX7S_CPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_MASK, + RXCDR_CFG1_MASK, + RXCDR_CFG2_MASK, + RXCDR_CFG3_MASK, + RXCDR_CFG4_MASK, + RXOUT_DIV_MASK, + TXOUT_DIV_MASK, + RX_DFE_LPM_CFG_MASK +}; + +/* Note bands run vertically from 1 to 4 */ +static const u16 gtx7s_cpll_channel_param_lut[GTX7S_CPLL_NUM_CHANNEL_DRP_REGS] + [GTX7S_CPLL_NUM_LINE_RATE_BANDS] = { + {0x20, 0x20, 0x20, 0x20 },/* RXCDR_CFG0 */ + {0x1010, 0x1020, 0x1040, 0x1040 },/* RXCDR_CFG1 */ + {0x23ff, 0x23ff, 0x23ff, 0x23ff },/* RXCDR_CFG2 */ + {0x0, 0x0, 0x0, 0x0 },/* RXCDR_CFG3 */ + {0x3, 0x3, 0x3, 0x3 },/* RXCDR_CFG4 */ + {0x3, 0x2, 0x1, 0x1 },/* RXOUT_DIV */ + {0x3, 0x2, 0x1, 0x1 },/* TXOUT_DIV */ + {0x904, 0x904, 0x904, 0x104 } /* RX_DFE_LPM_CFG */ +}; + +u32 get_gtx7s_cpll_address_lut(u32 lut_address) +{ + return gtx7s_cpll_channel_address_lut[lut_address]; +} + +u32 get_gtx7s_cpll_offset_lut(u32 lut_address) +{ + return gtx7s_cpll_channel_offset_lut[lut_address]; +} + +u32 get_gtx7s_cpll_mask_lut(u32 lut_address) +{ + return gtx7s_cpll_channel_mask_lut[lut_address]; +} + +u16 get_gtx7s_cpll_param_lut(u32 param_address, u32 band_address) +{ + return gtx7s_cpll_channel_param_lut[param_address][band_address]; +} diff --git a/drivers/misc/jesd204b/gtx7s_cpll_bands.h b/drivers/misc/jesd204b/gtx7s_cpll_bands.h new file mode 100644 index 00000000000000..f53f20de2cda96 --- /dev/null +++ b/drivers/misc/jesd204b/gtx7s_cpll_bands.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#ifndef GTX7S_CPLL_BANDS_H_ +#define GTX7S_CPLL_BANDS_H_ + +#define GTX7S_CPLL_NUM_CHANNEL_DRP_REGS 8 +#define GTX7S_CPLL_NUM_LINE_RATE_BANDS 4 + +u32 get_gtx7s_cpll_address_lut(u32); +u32 get_gtx7s_cpll_offset_lut(u32); +u32 get_gtx7s_cpll_mask_lut(u32); +u16 get_gtx7s_cpll_param_lut(u32, u32); + +#endif /* GTX7S_CPLL_BANDS_H_ */ diff --git a/drivers/misc/jesd204b/gtx7s_qpll_bands.c b/drivers/misc/jesd204b/gtx7s_qpll_bands.c new file mode 100644 index 00000000000000..71e70a611bb71d --- /dev/null +++ b/drivers/misc/jesd204b/gtx7s_qpll_bands.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "s7_gtxe2_drp.h" +#include "gtx7s_qpll_bands.h" + +static const u32 gtx7s_qpll_channel_address_lut + [GTX7S_QPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_ADDR, + RXCDR_CFG1_ADDR, + RXCDR_CFG2_ADDR, + RXCDR_CFG3_ADDR, + RXCDR_CFG4_ADDR, + RXOUT_DIV_ADDR, + TXOUT_DIV_ADDR, + RX_DFE_LPM_CFG_ADDR, + QPLL_CFG0_ADDR, + QPLL_CFG1_ADDR +}; + +static const u32 gtx7s_qpll_channel_offset_lut + [GTX7S_QPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_OFFSET, + RXCDR_CFG1_OFFSET, + RXCDR_CFG2_OFFSET, + RXCDR_CFG3_OFFSET, + RXCDR_CFG4_OFFSET, + RXOUT_DIV_OFFSET, + TXOUT_DIV_OFFSET, + RX_DFE_LPM_CFG_OFFSET, + QPLL_CFG0_OFFSET, + QPLL_CFG1_OFFSET +}; + +static const u32 gtx7s_qpll_channel_mask_lut + [GTX7S_QPLL_NUM_CHANNEL_DRP_REGS] = { + RXCDR_CFG0_MASK, + RXCDR_CFG1_MASK, + RXCDR_CFG2_MASK, + RXCDR_CFG3_MASK, + RXCDR_CFG4_MASK, + RXOUT_DIV_MASK, + TXOUT_DIV_MASK, + RX_DFE_LPM_CFG_MASK, + QPLL_CFG0_MASK, + QPLL_CFG1_MASK +}; + +/* Note bands run vertically from 1 to 10 */ +static const u16 gtx7s_qpll_channel_param_lut[GTX7S_QPLL_NUM_CHANNEL_DRP_REGS] + [GTX7S_QPLL_NUM_LINE_RATE_BANDS] = { +{0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20},/* RXCDR_CFG0 */ +{0x1008, 0x1010, 0x1020, 0x1010, 0x1020, 0x1040, 0x1020, 0x1040, 0x1040, 0x1040},/* RXCDR_CFG1 */ +{0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff, 0x23ff},/* RXCDR_CFG2 */ +{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* RXCDR_CFG3 */ +{0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3},/* RXCDR_CFG4 */ +{0x3e8, 0x4, 0x2, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1},/* RXOUT_DIV */ +{0x3e8, 0x4, 0x2, 0x3, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1},/* TXOUT_DIV */ +{0x904, 0x904, 0x904, 0x904, 0x904, 0x904, 0x904, 0x904, 0x104, 0x104},/* RX_DFE_LPM_CFG */ +{0x1c1, 0x1c1, 0x1c1, 0x181, 0x1c1, 0x1c1, 0x181, 0x1c1, 0x1c1, 0x181},/* QPLL_CFG0 */ +{0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68} /* QPLL_CFG1 */ +}; + +u32 get_gtx7s_qpll_address_lut(u32 lut_address) +{ + return gtx7s_qpll_channel_address_lut[lut_address]; +} + +u32 get_gtx7s_qpll_offset_lut(u32 lut_address) +{ + return gtx7s_qpll_channel_offset_lut[lut_address]; +} + +u32 get_gtx7s_qpll_mask_lut(u32 lut_address) +{ + return gtx7s_qpll_channel_mask_lut[lut_address]; +} + +u16 get_gtx7s_qpll_param_lut(u32 param_address, u32 band_address) +{ + return gtx7s_qpll_channel_param_lut[param_address][band_address]; +} diff --git a/drivers/misc/jesd204b/gtx7s_qpll_bands.h b/drivers/misc/jesd204b/gtx7s_qpll_bands.h new file mode 100644 index 00000000000000..8b9f6c24efb428 --- /dev/null +++ b/drivers/misc/jesd204b/gtx7s_qpll_bands.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +#ifndef GTX7S_QPLL_BANDS_H_ +#define GTX7S_QPLL_BANDS_H_ + +#define GTX7S_QPLL_NUM_CHANNEL_DRP_REGS 10 +#define GTX7S_QPLL_NUM_LINE_RATE_BANDS 10 + +u32 get_gtx7s_qpll_address_lut(u32); +u32 get_gtx7s_qpll_offset_lut(u32); +u32 get_gtx7s_qpll_mask_lut(u32); +u16 get_gtx7s_qpll_param_lut(u32, u32); + +#endif /* GTX7S_QPLL_BANDS_H_ */ diff --git a/drivers/misc/jesd204b/jesd_phy.c b/drivers/misc/jesd204b/jesd_phy.c new file mode 100644 index 00000000000000..c35d9433d0fc80 --- /dev/null +++ b/drivers/misc/jesd204b/jesd_phy.c @@ -0,0 +1,384 @@ +/* + * Jesd204b phy support + * + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include "jesd_phy.h" +#include "gtx7s_cpll_bands.h" +#include "gtx7s_qpll_bands.h" + +#define PLATFORM_JESD204_PHY_ADDR 0x41E10000 +#define JESD_PHY_LOOP_OFF 0 +#define JESD_PHY_LOOP_PCS 1 +#define JESD_PHY_LOOP_PMA 2 +#define JESD_PHY_LOOP_MAX 2 + +static inline void jesd204b_phy_write(struct jesd204b_phy_state *st, + unsigned reg, unsigned val) +{ + iowrite32(val, st->phy + reg); +} + +static inline unsigned int jesd204b_phy_read(struct jesd204b_phy_state *st, + unsigned reg) +{ + return ioread32(st->phy + reg); +} + +#define NUM_GT_CHANNELS 8 + +#define QPLL 0x3 /* QPLL (7 series) QPLL1 (UltraScale) */ +#define QPLL0 0x2 /* (UltraScale Only) */ +#define CPLL 0x0 + +#define DRPREAD BIT(30) +#define DRPWRITE BIT(31) + +#define NR_COMMON_DRP_INTERFACES 0x008 +#define NR_TRANS_DRP_INTERFACES 0x00C + +#define CHANNEL_DRP_BASE 0x200 +#define CHANNEL_DRP_ADDR 0x204 +#define CHANNEL_DRP_DREAD 0x20C +#define CHANNEL_DRP_DWRITE 0x208 +#define CHANNEL_DRP_STAT 0x214 + +#define CHANNEL_XCVR_SEL 0x400 +#define CHANNEL_XCVR_TXPLL 0x40C +#define CHANNEL_XCVR_RXPLL 0x410 +#define CHANNEL_XCVR_LOOPB 0x41C + +static u32 read_channel_drp_reg(struct jesd204b_phy_state *st, u32 addr) +{ + u32 temp; + + jesd204b_phy_write(st, CHANNEL_DRP_ADDR, (DRPREAD | addr)); + temp = jesd204b_phy_read(st, CHANNEL_DRP_DREAD); + return temp; +} + +static void write_channel_drp_reg(struct jesd204b_phy_state *st, u32 addr, + u32 data) +{ + u32 loop = 10; + + jesd204b_phy_write(st, CHANNEL_DRP_DWRITE, data); + jesd204b_phy_write(st, CHANNEL_DRP_ADDR, (DRPWRITE | addr)); + + do { + if (!jesd204b_phy_read(st, CHANNEL_DRP_STAT)) + break; + msleep(1); + } while (loop--); + + if (!loop) + dev_err(st->dev, "DRP wait timeout\n"); +} + +static void read_plls(struct jesd204b_phy_state *st) +{ + int i; + int pll = st->pll; + u32 no_of_common_drp_interfaces = 1; + + if (st->pll == CPLL) + no_of_common_drp_interfaces = jesd204b_phy_read( + st, NR_TRANS_DRP_INTERFACES); + else + no_of_common_drp_interfaces = jesd204b_phy_read( + st, NR_COMMON_DRP_INTERFACES); + + for (i = 0; i < no_of_common_drp_interfaces; i++) { + jesd204b_phy_write(st, CHANNEL_XCVR_SEL, i); + pll = jesd204b_phy_read(st, CHANNEL_XCVR_TXPLL); + pll = jesd204b_phy_read(st, CHANNEL_XCVR_RXPLL); + } +} + +static void configure_plls(struct jesd204b_phy_state *st, u32 pll) +{ + int i; + u32 no_of_common_drp_interfaces; + + if (pll == CPLL) + no_of_common_drp_interfaces = jesd204b_phy_read( + st, NR_TRANS_DRP_INTERFACES); + else + no_of_common_drp_interfaces = jesd204b_phy_read( + st, NR_COMMON_DRP_INTERFACES); + + for (i = 0; i < no_of_common_drp_interfaces; i++) { + jesd204b_phy_write(st, CHANNEL_XCVR_SEL, i); + jesd204b_phy_write(st, CHANNEL_XCVR_TXPLL, pll); + jesd204b_phy_write(st, CHANNEL_XCVR_RXPLL, pll); + } +} + +static void configure_channel_drp(struct jesd204b_phy_state *st, u32 setting) +{ + u32 i, j, addr, temp, no_of_common_drp_interfaces; + u32 no_channel_drp_reg = GTX7S_QPLL_NUM_CHANNEL_DRP_REGS; + + no_of_common_drp_interfaces = jesd204b_phy_read( + st, NR_TRANS_DRP_INTERFACES); + + if (st->pll == CPLL) + no_channel_drp_reg = GTX7S_CPLL_NUM_CHANNEL_DRP_REGS; + for (i = 0; i < no_of_common_drp_interfaces; i++) { + jesd204b_phy_write(st, CHANNEL_DRP_BASE, i); + for (j = 0; j < no_channel_drp_reg; j++) { + /* Get the register address */ + if (st->pll == QPLL) { + addr = get_gtx7s_qpll_address_lut(j); + + /* Read the register */ + temp = read_channel_drp_reg(st, addr); + + temp &= (0xFFFF ^ (get_gtx7s_qpll_mask_lut(j))); + temp |= ((get_gtx7s_qpll_param_lut(j, setting) + << get_gtx7s_qpll_offset_lut(j)) + & get_gtx7s_qpll_mask_lut(j)); + } else { + addr = get_gtx7s_cpll_address_lut(j); + + temp = read_channel_drp_reg(st, addr); + + temp &= (0xFFFF ^ (get_gtx7s_cpll_mask_lut(j))); + temp |= ((get_gtx7s_cpll_param_lut(j, setting) + << get_gtx7s_cpll_offset_lut(j)) + & get_gtx7s_cpll_mask_lut(j)); + } + write_channel_drp_reg(st, addr, temp); + } + } +} + +void jesd204_phy_set_speed(struct jesd204b_phy_state *st, u32 band) +{ + /* make sure we have the correct PLL's selected. */ + configure_channel_drp(st, band); +} + +static void jesd204_phy_init(struct jesd204b_phy_state *st, int line_rate) +{ + jesd204_phy_set_speed(st, line_rate); +} + +int jesd204_phy_set_loop(struct jesd204b_phy_state *st, u32 loopval) +{ + int i; + u32 no_of_channels; + + no_of_channels = jesd204b_phy_read(st, NR_COMMON_DRP_INTERFACES); + + if (loopval > JESD_PHY_LOOP_MAX) + return -EINVAL; + + for (i = 0; i < no_of_channels ; i++) { + jesd204b_phy_write(st, CHANNEL_XCVR_SEL, i); + jesd204b_phy_write(st, CHANNEL_XCVR_LOOPB, loopval); + } + return 0; +} + +static ssize_t jesd204b_pll_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204b_phy_state *st = dev_get_drvdata(dev); + + read_plls(st); + if (st->pll == CPLL) + return sprintf(buf, "cpll\n"); + return sprintf(buf, "qpll\n"); +} + +static ssize_t jesd204b_configure_pll(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct jesd204b_phy_state *st = dev_get_drvdata(dev); + unsigned val; + int ret; + + ret = kstrtouint(buf, 0, &val); + if (!ret) + return 0; + + if (val > QPLL) { + dev_err(dev, "Setting the pll to %d valid values\n" + "00 = CPLL\n" + "10 = QPLL0 (UltraScale Only)\n" + "11 = QPLL (7 series) QPLL1 (UltraScale)\n", val); + return 0; + } + st->pll = val; + configure_plls(st, val); + + return count; +} + +static DEVICE_ATTR(configure_pll, S_IWUSR | S_IRUSR, jesd204b_pll_read, + jesd204b_configure_pll); + +static ssize_t jesd204b_linerate_read(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct jesd204b_phy_state *st = dev_get_drvdata(dev); + + return sprintf(buf, "0x%X\n", st->band); +} + +static ssize_t jesd204b_linerate_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct jesd204b_phy_state *st = dev_get_drvdata(dev); + int ret; + /* Low frequencies are not supported by qpll */ + + ret = kstrtouint(buf, 0, &st->band); + if (ret) + return ret; + + dev_info(dev, "Setting the line rate to band to %d\n", st->band); + /* QPLL - freq options in phy + * 62.5 + * 78.125 + * 94.697 + * 97.656 + * 125.000 + * 156.25 + * 187.5 + * 189.394 + * 195.313 + * 234.375 + * 250.000 + * 284.091 + * 292.969 + */ + if (st->band == 2) + clk_set_rate(st->clk, 62500000); /* 2.5G */ + else if (st->band == 4) + clk_set_rate(st->clk, 97656000); /* 3.9G */ + else if (st->band == 6) + clk_set_rate(st->clk, 125000000); /* 5G */ + else if (st->band == 7) + clk_set_rate(st->clk, 156250000); /* 6.25G */ + else if (st->band == 8) + clk_set_rate(st->clk, 195313000); /* 7.812G */ + else if (st->band == 9) + clk_set_rate(st->clk, 250000000);/* 10G */ + + jesd204_phy_init(st, st->band); + + return count; +} + +static DEVICE_ATTR(line_rate_band, S_IWUSR | S_IRUSR, jesd204b_linerate_read, + jesd204b_linerate_write); + +/* Match table for of_platform binding */ +static const struct of_device_id jesd204b_phy_of_match[] = { + { .compatible = "xlnx,jesd204-phy-2.0", }, + { /* end of list */ }, +}; + +static int jesd204b_phy_probe(struct platform_device *pdev) +{ + struct jesd204b_phy_state *st; + struct resource *mem; /* IO mem resources */ + int ret; + u32 ref_clk; + + st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL); + if (!st) + return -ENOMEM; + + st->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(st->clk)) + return -EPROBE_DEFER; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + st->phy = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(st->phy)) { + dev_err(&pdev->dev, "Failed ioremap\n"); + return PTR_ERR(st->phy); + } + st->dev = &pdev->dev; + platform_set_drvdata(pdev, st); + + ret = of_property_read_u32(pdev->dev.of_node, "xlnx,lanes", + &st->lanes); + if (ret) { + dev_err(&pdev->dev, "Failed to read required dt property\n"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "xlnx,pll-selection", + &st->pll); + if (ret) { + dev_err(&pdev->dev, "Failed to read required dt property\n"); + return ret; + } + ret = of_property_read_u32(pdev->dev.of_node, "xlnx,gt-refclk-freq", + &ref_clk); + if (ret) { + dev_err(&pdev->dev, "Failed to read required dt property\n"); + return ret; + } + + clk_set_rate(st->clk, (unsigned long)ref_clk); + device_create_file(&pdev->dev, &dev_attr_configure_pll); + device_create_file(&pdev->dev, &dev_attr_line_rate_band); + + ret = clk_prepare_enable(st->clk); + if (ret) { + dev_err(&pdev->dev, "Unable to enable clock.\n"); + return ret; + } + + return 0; +} + +static int jesd204b_phy_remove(struct platform_device *pdev) +{ + struct jesd204b_phy_state *st = platform_get_drvdata(pdev); + + clk_disable_unprepare(st->clk); + clk_put(st->clk); + device_remove_file(&pdev->dev, &dev_attr_configure_pll); + device_remove_file(&pdev->dev, &dev_attr_line_rate_band); + return 0; +} + +static struct platform_driver jesd204b_driver = { + .driver = { + .name = "jesd204b_phy", + .of_match_table = jesd204b_phy_of_match, + }, + .probe = jesd204b_phy_probe, + .remove = jesd204b_phy_remove, +}; + +module_platform_driver(jesd204b_driver); + +MODULE_AUTHOR("Shubhrajyoti Datta "); +MODULE_DESCRIPTION("AXI-JESD204B Phy Interface Module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/jesd204b/jesd_phy.h b/drivers/misc/jesd204b/jesd_phy.h new file mode 100644 index 00000000000000..c15328532c3f6f --- /dev/null +++ b/drivers/misc/jesd204b/jesd_phy.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef JESD_PHY_H_ +#define JESD_PHY_H_ + +#include +#include +#include +#include +#include +#include +#include + +struct jesd204b_phy_state { + struct device *dev; + void __iomem *phy; + struct clk *clk; + u32 vers_id; + u32 addr; + u32 lanes; + u32 band; + u32 pll; + unsigned long rate; +}; + +int jesd204_phy_set_loop(struct jesd204b_phy_state *st, u32 loopval); + +#endif /* JESD_PHY_H_ */ diff --git a/drivers/misc/jesd204b/s7_gtxe2_drp.h b/drivers/misc/jesd204b/s7_gtxe2_drp.h new file mode 100644 index 00000000000000..f08a211432bda3 --- /dev/null +++ b/drivers/misc/jesd204b/s7_gtxe2_drp.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2014 - 2015 Xilinx, Inc. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#define TXOUT_DIV_ADDR 0x88 +#define TXOUT_DIV_MASK 0x70 +#define TXOUT_DIV_OFFSET 0x4 +#define TXOUT_DIV_WIDTH 0x3 +#define TXOUT_DIV_DEFAULT 0x0 + +#define RXOUT_DIV_ADDR 0x88 +#define RXOUT_DIV_MASK 0x7 +#define RXOUT_DIV_OFFSET 0x0 +#define RXOUT_DIV_WIDTH 0x3 +#define RXOUT_DIV_DEFAULT 0x0 + +#define RXCDR_CFG0_ADDR 0xa8 +#define RXCDR_CFG0_MASK 0xffff +#define RXCDR_CFG0_OFFSET 0x0 +#define RXCDR_CFG0_WIDTH 0x10 +#define RXCDR_CFG0_DEFAULT 0x0 + +#define RXCDR_CFG1_ADDR 0xa9 +#define RXCDR_CFG1_MASK 0xffff +#define RXCDR_CFG1_OFFSET 0x0 +#define RXCDR_CFG1_WIDTH 0x10 +#define RXCDR_CFG1_DEFAULT 0x0 + +#define RXCDR_CFG2_ADDR 0xaa +#define RXCDR_CFG2_MASK 0xffff +#define RXCDR_CFG2_OFFSET 0x0 +#define RXCDR_CFG2_WIDTH 0x10 +#define RXCDR_CFG2_DEFAULT 0x0 + +#define RXCDR_CFG3_ADDR 0xab +#define RXCDR_CFG3_MASK 0xffff +#define RXCDR_CFG3_OFFSET 0x0 +#define RXCDR_CFG3_WIDTH 0x10 +#define RXCDR_CFG3_DEFAULT 0x0 + +#define RXCDR_CFG4_ADDR 0xac +#define RXCDR_CFG4_MASK 0xff +#define RXCDR_CFG4_OFFSET 0x0 +#define RXCDR_CFG4_WIDTH 0x8 +#define RXCDR_CFG4_DEFAULT 0x0 + +#define RX_DFE_LPM_CFG_ADDR 0x29 +#define RX_DFE_LPM_CFG_MASK 0xffff +#define RX_DFE_LPM_CFG_OFFSET 0x0 +#define RX_DFE_LPM_CFG_WIDTH 0x10 +#define RX_DFE_LPM_CFG_DEFAULT 0x0 + +#define QPLL_CFG0_ADDR 0x32 +#define QPLL_CFG0_MASK 0xffff +#define QPLL_CFG0_OFFSET 0x0 +#define QPLL_CFG0_WIDTH 0x10 +#define QPLL_CFG0_DEFAULT 0x0 + +#define QPLL_CFG1_ADDR 0x33 +#define QPLL_CFG1_MASK 0x7ff +#define QPLL_CFG1_OFFSET 0x0 +#define QPLL_CFG1_WIDTH 0xb +#define QPLL_CFG1_DEFAULT 0x0 + +#define QPLL_REFCLK_DIV_M_ADDR 0x33 +#define QPLL_REFCLK_DIV_M_MASK 0xf800 +#define QPLL_REFCLK_DIV_M_OFFSET 0xb +#define QPLL_REFCLK_DIV_M_WIDTH 0x5 +#define QPLL_REFCLK_DIV_M_DEFAULT 0x0 + +#define QPLL_FBDIV_N_ADDR 0x36 +#define QPLL_FBDIV_N_MASK 0x3ff +#define QPLL_FBDIV_N_OFFSET 0x0 +#define QPLL_FBDIV_N_WIDTH 0xa +#define QPLL_FBDIV_N_DEFAULT 0x0 + +#define QPLL_FBDIV_RATIO_ADDR 0x37 +#define QPLL_FBDIV_RATIO_MASK 0x40 +#define QPLL_FBDIV_RATIO_OFFSET 0x6 +#define QPLL_FBDIV_RATIO_WIDTH 0x1 +#define QPLL_FBDIV_RATIO_DEFAULT 0x0 + +#define CPLL_CFG0_ADDR 0x5c +#define CPLL_CFG0_MASK 0xff00 +#define CPLL_CFG0_OFFSET 0x8 +#define CPLL_CFG0_WIDTH 0x8 +#define CPLL_CFG0_DEFAULT 0x0 + +#define CPLL_CFG1_ADDR 0x5d +#define CPLL_CFG1_MASK 0xffff +#define CPLL_CFG1_OFFSET 0x0 +#define CPLL_CFG1_WIDTH 0x10 +#define CPLL_CFG1_DEFAULT 0x0 + +#define CPLL_REFCLK_DIV_M_ADDR 0x5e +#define CPLL_REFCLK_DIV_M_MASK 0x1f00 +#define CPLL_REFCLK_DIV_M_OFFSET 0x8 +#define CPLL_REFCLK_DIV_M_WIDTH 0x5 +#define CPLL_REFCLK_DIV_M_DEFAULT 0x0 + +#define CPLL_FB_DIV_45_N1_ADDR 0x5e +#define CPLL_FB_DIV_45_N1_MASK 0x80 +#define CPLL_FB_DIV_45_N1_OFFSET 0x7 +#define CPLL_FB_DIV_45_N1_WIDTH 0x1 +#define CPLL_FB_DIV_45_N1_DEFAULT 0x0 + +#define CPLL_FBDIV_N2_ADDR 0x5e +#define CPLL_FBDIV_N2_MASK 0x7f +#define CPLL_FBDIV_N2_OFFSET 0x0 +#define CPLL_FBDIV_N2_WIDTH 0x7 +#define CPLL_FBDIV_N2_DEFAULT 0x0 diff --git a/drivers/misc/jesd204b/xilinx_jesd204b.c b/drivers/misc/jesd204b/xilinx_jesd204b.c index 7ff9ab12b6ab26..304557c8978e61 100644 --- a/drivers/misc/jesd204b/xilinx_jesd204b.c +++ b/drivers/misc/jesd204b/xilinx_jesd204b.c @@ -24,7 +24,6 @@ #include "xilinx_jesd204b.h" - struct child_clk { struct clk_hw hw; struct jesd204b_state *st; @@ -35,24 +34,24 @@ struct child_clk { #define to_clk_priv(_hw) container_of(_hw, struct child_clk, hw) static inline void jesd204b_write(struct jesd204b_state *st, - unsigned reg, unsigned val) + unsigned int reg, unsigned int val) { iowrite32(val, st->regs + reg); } static inline unsigned int jesd204b_read(struct jesd204b_state *st, - unsigned reg) + unsigned int reg) { return ioread32(st->regs + reg); } static ssize_t jesd204b_laneinfo_read(struct device *dev, struct device_attribute *attr, - char *buf, unsigned lane) + char *buf, unsigned int lane) { struct jesd204b_state *st = dev_get_drvdata(dev); int ret; - unsigned val1, val2, val3; + unsigned int val1, val2, val3; val1 = jesd204b_read(st, XLNX_JESD204_REG_ID_L(lane)); val2 = jesd204b_read(st, XLNX_JESD204_REG_LANE_F(lane)); @@ -118,7 +117,7 @@ static ssize_t jesd204b_lane##_x##_info_read(struct device *dev, \ { \ return jesd204b_laneinfo_read(dev, attr, buf, _x); \ } \ -static DEVICE_ATTR(lane##_x##_info, S_IRUSR, jesd204b_lane##_x##_info_read, \ +static DEVICE_ATTR(lane##_x##_info, 0400, jesd204b_lane##_x##_info_read, \ NULL) JESD_LANE(0); @@ -132,10 +131,10 @@ JESD_LANE(7); static ssize_t jesd204b_lane_syscstat_read(struct device *dev, struct device_attribute *attr, - char *buf, unsigned lane) + char *buf, unsigned int lane) { + unsigned int stat; struct jesd204b_state *st = dev_get_drvdata(dev); - unsigned stat; stat = jesd204b_read(st, XLNX_JESD204_REG_SYNC_ERR_STAT); @@ -153,7 +152,7 @@ static ssize_t jesd204b_lane##_x##_syncstat_read(struct device *dev, \ { \ return jesd204b_lane_syscstat_read(dev, attr, buf, _x); \ } \ -static DEVICE_ATTR(lane##_x##_syncstat, S_IRUSR, \ +static DEVICE_ATTR(lane##_x##_syncstat, 0400, \ jesd204b_lane##_x##_syncstat_read, NULL) JESD_SYNCSTAT_LANE(0); @@ -170,7 +169,7 @@ static ssize_t jesd204b_reg_write(struct device *dev, const char *buf, size_t count) { struct jesd204b_state *st = dev_get_drvdata(dev); - unsigned val; + unsigned int val; int ret; ret = sscanf(buf, "%i %i", &st->addr, &val); @@ -189,7 +188,7 @@ static ssize_t jesd204b_reg_read(struct device *dev, return sprintf(buf, "0x%X\n", jesd204b_read(st, st->addr)); } -static DEVICE_ATTR(reg_access, S_IWUSR | S_IRUSR, jesd204b_reg_read, +static DEVICE_ATTR(reg_access, 0600, jesd204b_reg_read, jesd204b_reg_write); static ssize_t jesd204b_syncreg_read(struct device *dev, @@ -202,9 +201,9 @@ static ssize_t jesd204b_syncreg_read(struct device *dev, XLNX_JESD204_REG_SYNC_STATUS)); } -static DEVICE_ATTR(sync_status, S_IRUSR, jesd204b_syncreg_read, NULL); +static DEVICE_ATTR(sync_status, 0400, jesd204b_syncreg_read, NULL); -static unsigned long jesd204b_clk_recalc_rate(struct clk_hw *hw, +static unsigned int long jesd204b_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { return parent_rate; @@ -250,7 +249,7 @@ static int jesd204b_probe(struct platform_device *pdev) struct clk *clk; struct child_clk *clk_priv; struct clk_init_data init; - unsigned frmcnt, bytecnt, subclass, val; + unsigned int val; int ret; clk = devm_clk_get(&pdev->dev, NULL); @@ -276,27 +275,6 @@ static int jesd204b_probe(struct platform_device *pdev) clk_set_rate(st->clk, 156250000); st->rate = clk_get_rate(clk); - ret = of_property_read_u32(pdev->dev.of_node, - "xlnx,frames-per-multiframe", &frmcnt); - if (ret) { - dev_err(&pdev->dev, "Failed to read required dt property\n"); - return ret; - } - - ret = of_property_read_u32(pdev->dev.of_node, "xlnx,bytes-per-frame", - &bytecnt); - if (ret) { - dev_err(&pdev->dev, "Failed to read required dt property\n"); - return ret; - } - - ret = of_property_read_u32(pdev->dev.of_node, "xlnx,subclass", - &subclass); - if (ret) { - dev_err(&pdev->dev, "Failed to read required dt property\n"); - return ret; - } - of_property_read_u32(pdev->dev.of_node, "xlnx,node-is-transmit", &st->transmit); @@ -307,7 +285,7 @@ static int jesd204b_probe(struct platform_device *pdev) jesd204b_write(st, XLNX_JESD204_REG_RESET, XLNX_JESD204_RESET); while (!jesd204b_read(st, XLNX_JESD204_REG_RESET)) - msleep(1); + msleep(20); jesd204b_write(st, XLNX_JESD204_REG_ILA_CTRL, (of_property_read_bool(pdev->dev.of_node, @@ -322,17 +300,6 @@ static int jesd204b_probe(struct platform_device *pdev) "xlnx,sysref-always-enable") ? XLNX_JESD204_ALWAYS_SYSREF_EN : 0)); - jesd204b_write(st, XLNX_JESD204_REG_ILA_MFC, - XLNX_JESD204_ILA_MFC(frmcnt)); - - jesd204b_write(st, XLNX_JESD204_REG_OCTETS_PER_FRAME, - XLNX_JESD204_OCTETS_PER_FRAME(bytecnt)); - - jesd204b_write(st, XLNX_JESD204_REG_FRAMES_PER_MFRAME, - XLNX_JESD204_FRAMES_PER_MFRAME(frmcnt)); - - jesd204b_write(st, XLNX_JESD204_REG_SUBCLASS, subclass); - device_create_file(&pdev->dev, &dev_attr_reg_access); device_create_file(&pdev->dev, &dev_attr_sync_status);