lkml.org 
[lkml]   [2021]   [May]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH v2 04/18] phy: cdns-dphy: Add Rx support
    From
    Date
    On 26/05/2021 18:22, Pratyush Yadav wrote:
    > The Cadence DPHY can be used to receive image data over the CSI-2
    > protocol. Add support for Rx mode. The programming sequence differs from
    > the Tx mode so it is added as a separate set of hooks to isolate the two
    > paths.
    >
    > The PHY is in Tx mode by default and it needs to be set in Rx mode by
    > setting the submode to PHY_MIPI_DPHY_SUBMODE_RX in the set_mode()
    > callback.
    >
    > Signed-off-by: Pratyush Yadav <p.yadav@ti.com>
    > ---
    >
    > (no changes since v1)
    >
    > drivers/phy/cadence/cdns-dphy.c | 237 ++++++++++++++++++++++++++++++++
    > 1 file changed, 237 insertions(+)
    >
    > diff --git a/drivers/phy/cadence/cdns-dphy.c b/drivers/phy/cadence/cdns-dphy.c
    > index 7d5f7b333893..7bbca679e2bb 100644
    > --- a/drivers/phy/cadence/cdns-dphy.c
    > +++ b/drivers/phy/cadence/cdns-dphy.c
    > @@ -1,11 +1,14 @@
    > // SPDX-License-Identifier: GPL-2.0+
    > /*
    > * Copyright: 2017-2018 Cadence Design Systems, Inc.
    > + * Copyright (C) 2021 Texas Instruments Incorporated - https://www.ti.com/
    > */
    >
    > #include <linux/bitops.h>
    > +#include <linux/bitfield.h>
    > #include <linux/clk.h>
    > #include <linux/io.h>
    > +#include <linux/iopoll.h>
    > #include <linux/module.h>
    > #include <linux/of_address.h>
    > #include <linux/of_device.h>
    > @@ -25,10 +28,14 @@
    > #define DPHY_PMA_RCLK(reg) (0x600 + (reg))
    > #define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg))
    > #define DPHY_PCS(reg) (0xb00 + (reg))
    > +#define DPHY_ISO(reg) (0xc00 + (reg))
    >
    > #define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
    > #define DPHY_CMN_SSM_EN BIT(0)
    > +#define DPHY_CMN_RX_BANDGAP_TIMER_MASK GENMASK(8, 1)
    > #define DPHY_CMN_TX_MODE_EN BIT(9)
    > +#define DPHY_CMN_RX_MODE_EN BIT(10)
    > +#define DPHY_CMN_RX_BANDGAP_TIMER 0x14
    >
    > #define DPHY_CMN_PWM DPHY_PMA_CMN(0x40)
    > #define DPHY_CMN_PWM_DIV(x) ((x) << 20)
    > @@ -45,10 +52,27 @@
    > #define DPHY_CMN_OPDIV_FROM_REG BIT(6)
    > #define DPHY_CMN_OPDIV(x) ((x) << 7)
    >
    > +#define DPHY_BAND_CFG DPHY_PCS(0x0)
    > +#define DPHY_BAND_CFG_LEFT_BAND GENMASK(4, 0)
    > +#define DPHY_BAND_CFG_RIGHT_BAND GENMASK(9, 5)
    > +
    > #define DPHY_PSM_CFG DPHY_PCS(0x4)
    > #define DPHY_PSM_CFG_FROM_REG BIT(0)
    > #define DPHY_PSM_CLK_DIV(x) ((x) << 1)
    >
    > +#define DPHY_POWER_ISLAND_EN_DATA DPHY_PCS(0x8)
    > +#define DPHY_POWER_ISLAND_EN_DATA_VAL 0xaaaaaaaa
    > +#define DPHY_POWER_ISLAND_EN_CLK DPHY_PCS(0xc)
    > +#define DPHY_POWER_ISLAND_EN_CLK_VAL 0xaa
    > +
    > +#define DPHY_ISO_CL_CTRL_L DPHY_ISO(0x10)
    > +#define DPHY_ISO_DL_CTRL_L0 DPHY_ISO(0x14)
    > +#define DPHY_ISO_DL_CTRL_L1 DPHY_ISO(0x20)
    > +#define DPHY_ISO_DL_CTRL_L2 DPHY_ISO(0x30)
    > +#define DPHY_ISO_DL_CTRL_L3 DPHY_ISO(0x3c)
    > +#define DPHY_ISO_LANE_READY_BIT 0
    > +#define DPHY_ISO_LANE_READY_TIMEOUT_MS 100UL
    > +
    > #define DSI_HBP_FRAME_OVERHEAD 12
    > #define DSI_HSA_FRAME_OVERHEAD 14
    > #define DSI_HFP_FRAME_OVERHEAD 6
    > @@ -57,6 +81,9 @@
    > #define DSI_NULL_FRAME_OVERHEAD 6
    > #define DSI_EOT_PKT_SIZE 4
    >
    > +#define DPHY_LANES_MIN 1
    > +#define DPHY_LANES_MAX 4
    > +
    > struct cdns_dphy_cfg {
    > u8 pll_ipdiv;
    > u8 pll_opdiv;
    > @@ -312,6 +339,214 @@ static const struct cdns_dphy_ops tx_ref_dphy_ops = {
    > .set_psm_div = cdns_dphy_ref_set_psm_div,
    > };
    >
    > +static int cdns_dphy_rx_power_on(struct cdns_dphy *dphy)
    > +{
    > + /* Start RX state machine. */
    > + writel(DPHY_CMN_SSM_EN | DPHY_CMN_RX_MODE_EN |
    > + FIELD_PREP(DPHY_CMN_RX_BANDGAP_TIMER_MASK,
    > + DPHY_CMN_RX_BANDGAP_TIMER),
    > + dphy->regs + DPHY_CMN_SSM);
    > +
    > + return 0;
    > +}
    > +
    > +static int cdns_dphy_rx_power_off(struct cdns_dphy *dphy)
    > +{
    > + writel(0, dphy->regs + DPHY_CMN_SSM);
    > +
    > + return 0;
    > +}
    > +
    > +static int cdns_dphy_rx_get_band_ctrl(unsigned long hs_clk_rate)
    > +{
    > + unsigned int rate = hs_clk_rate / 1000000UL;
    > +
    > + if (rate < 80 || rate >= 2500)
    > + return -EOPNOTSUPP;
    > +
    > + if (rate >= 80 && rate < 100)
    > + return 0;
    > +
    > + if (rate >= 100 && rate < 120)
    > + return 1;
    > +
    > + if (rate >= 120 && rate < 160)
    > + return 2;
    > +
    > + if (rate >= 160 && rate < 200)
    > + return 3;
    > +
    > + if (rate >= 200 && rate < 240)
    > + return 4;
    > +
    > + if (rate >= 240 && rate < 280)
    > + return 5;
    > +
    > + if (rate >= 280 && rate < 320)
    > + return 6;
    > +
    > + if (rate >= 320 && rate < 360)
    > + return 7;
    > +
    > + if (rate >= 360 && rate < 400)
    > + return 8;
    > +
    > + if (rate >= 400 && rate < 480)
    > + return 9;
    > +
    > + if (rate >= 480 && rate < 560)
    > + return 10;
    > +
    > + if (rate >= 560 && rate < 640)
    > + return 11;
    > +
    > + if (rate >= 640 && rate < 720)
    > + return 12;
    > +
    > + if (rate >= 720 && rate < 800)
    > + return 13;
    > +
    > + if (rate >= 800 && rate < 880)
    > + return 14;
    > +
    > + if (rate >= 880 && rate < 1040)
    > + return 15;
    > +
    > + if (rate >= 1040 && rate < 1200)
    > + return 16;
    > +
    > + if (rate >= 1200 && rate < 1350)
    > + return 17;
    > +
    > + if (rate >= 1350 && rate < 1500)
    > + return 18;
    > +
    > + if (rate >= 1500 && rate < 1750)
    > + return 19;
    > +
    > + if (rate >= 1750 && rate < 2000)
    > + return 20;
    > +
    > + if (rate >= 2000 && rate < 2250)
    > + return 21;
    > +
    > + if (rate >= 2250 && rate < 2500)
    > + return 22;
    > +

    All the above could be handled with a simple table and a for loop.

    > + /* Unreachable. */
    > + WARN(1, "Reached unreachable code.");
    > + return -EINVAL;
    > +}
    > +
    > +static int cdns_dphy_rx_wait_for_bit(void __iomem *addr, unsigned int bit)
    > +{
    > + u32 val;
    > +
    > + return readl_relaxed_poll_timeout(addr, val, val & BIT(bit), 10,
    > + DPHY_ISO_LANE_READY_TIMEOUT_MS * 1000);
    > +}
    > +
    > +static int cdns_dphy_rx_wait_lane_ready(struct cdns_dphy *dphy, int lanes)
    > +{
    > + void __iomem *reg = dphy->regs;
    > + int ret;
    > +
    > + if (lanes < DPHY_LANES_MIN || lanes > DPHY_LANES_MAX)
    > + return -EINVAL;
    > +
    > + /* Clock lane */
    > + ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_CL_CTRL_L,
    > + DPHY_ISO_LANE_READY_BIT);
    > + if (ret)
    > + return ret;
    > +
    > + /* Data lanes. Minimum one lane is mandatory. */
    > + ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_DL_CTRL_L0,
    > + DPHY_ISO_LANE_READY_BIT);
    > + if (ret)
    > + return ret;
    > +
    > + if (lanes < 2)
    > + return 0;
    > +
    > + ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_DL_CTRL_L1,
    > + DPHY_ISO_LANE_READY_BIT);
    > + if (ret)
    > + return ret;
    > +
    > + if (lanes < 3)
    > + return 0;
    > +
    > + ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_DL_CTRL_L2,
    > + DPHY_ISO_LANE_READY_BIT);
    > + if (ret)
    > + return ret;
    > +
    > + if (lanes < 4)
    > + return 0;
    > +
    > + ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_DL_CTRL_L3,
    > + DPHY_ISO_LANE_READY_BIT);
    > + if (ret)
    > + return ret;
    > +

    This, too, could be handled with an array (for the regs) and a for loop.

    Tomi

    \
     
     \ /
      Last update: 2021-05-28 08:10    [W:2.543 / U:0.032 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site