root/drivers/staging/media/omap4iss/iss_csiphy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. csiphy_lanes_config
  2. csiphy_set_power
  3. csiphy_dphy_config
  4. omap4iss_csiphy_config
  5. omap4iss_csiphy_acquire
  6. omap4iss_csiphy_release
  7. omap4iss_csiphy_init

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * TI OMAP4 ISS V4L2 Driver - CSI PHY module
   4  *
   5  * Copyright (C) 2012 Texas Instruments, Inc.
   6  *
   7  * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
   8  */
   9 
  10 #include <linux/delay.h>
  11 #include <linux/device.h>
  12 #include <linux/regmap.h>
  13 
  14 #include "../../../../arch/arm/mach-omap2/control.h"
  15 
  16 #include "iss.h"
  17 #include "iss_regs.h"
  18 #include "iss_csiphy.h"
  19 
  20 /*
  21  * csiphy_lanes_config - Configuration of CSIPHY lanes.
  22  *
  23  * Updates HW configuration.
  24  * Called with phy->mutex taken.
  25  */
  26 static void csiphy_lanes_config(struct iss_csiphy *phy)
  27 {
  28         unsigned int i;
  29         u32 reg;
  30 
  31         reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG);
  32 
  33         for (i = 0; i < phy->max_data_lanes; i++) {
  34                 reg &= ~(CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) |
  35                          CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i + 1));
  36                 reg |= (phy->lanes.data[i].pol ?
  37                         CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) : 0);
  38                 reg |= (phy->lanes.data[i].pos <<
  39                         CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i + 1));
  40         }
  41 
  42         reg &= ~(CSI2_COMPLEXIO_CFG_CLOCK_POL |
  43                  CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK);
  44         reg |= phy->lanes.clk.pol ? CSI2_COMPLEXIO_CFG_CLOCK_POL : 0;
  45         reg |= phy->lanes.clk.pos << CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT;
  46 
  47         iss_reg_write(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG, reg);
  48 }
  49 
  50 /*
  51  * csiphy_set_power
  52  * @power: Power state to be set.
  53  *
  54  * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
  55  */
  56 static int csiphy_set_power(struct iss_csiphy *phy, u32 power)
  57 {
  58         u32 reg;
  59         u8 retry_count;
  60 
  61         iss_reg_update(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG,
  62                        CSI2_COMPLEXIO_CFG_PWD_CMD_MASK,
  63                        power | CSI2_COMPLEXIO_CFG_PWR_AUTO);
  64 
  65         retry_count = 0;
  66         do {
  67                 udelay(1);
  68                 reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG)
  69                     & CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK;
  70 
  71                 if (reg != power >> 2)
  72                         retry_count++;
  73 
  74         } while ((reg != power >> 2) && (retry_count < 250));
  75 
  76         if (retry_count == 250) {
  77                 dev_err(phy->iss->dev, "CSI2 CIO set power failed!\n");
  78                 return -EBUSY;
  79         }
  80 
  81         return 0;
  82 }
  83 
  84 /*
  85  * csiphy_dphy_config - Configure CSI2 D-PHY parameters.
  86  *
  87  * Called with phy->mutex taken.
  88  */
  89 static void csiphy_dphy_config(struct iss_csiphy *phy)
  90 {
  91         u32 reg;
  92 
  93         /* Set up REGISTER0 */
  94         reg = phy->dphy.ths_term << REGISTER0_THS_TERM_SHIFT;
  95         reg |= phy->dphy.ths_settle << REGISTER0_THS_SETTLE_SHIFT;
  96 
  97         iss_reg_write(phy->iss, phy->phy_regs, REGISTER0, reg);
  98 
  99         /* Set up REGISTER1 */
 100         reg = phy->dphy.tclk_term << REGISTER1_TCLK_TERM_SHIFT;
 101         reg |= phy->dphy.tclk_miss << REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT;
 102         reg |= phy->dphy.tclk_settle << REGISTER1_TCLK_SETTLE_SHIFT;
 103         reg |= 0xb8 << REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT;
 104 
 105         iss_reg_write(phy->iss, phy->phy_regs, REGISTER1, reg);
 106 }
 107 
 108 /*
 109  * TCLK values are OK at their reset values
 110  */
 111 #define TCLK_TERM       0
 112 #define TCLK_MISS       1
 113 #define TCLK_SETTLE     14
 114 
 115 int omap4iss_csiphy_config(struct iss_device *iss,
 116                            struct v4l2_subdev *csi2_subdev)
 117 {
 118         struct iss_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
 119         struct iss_pipeline *pipe = to_iss_pipeline(&csi2_subdev->entity);
 120         struct iss_v4l2_subdevs_group *subdevs = pipe->external->host_priv;
 121         struct iss_csiphy_dphy_cfg csi2phy;
 122         int csi2_ddrclk_khz;
 123         struct iss_csiphy_lanes_cfg *lanes;
 124         unsigned int used_lanes = 0;
 125         u32 cam_rx_ctrl;
 126         unsigned int i;
 127 
 128         lanes = &subdevs->bus.csi2.lanecfg;
 129 
 130         /*
 131          * SCM.CONTROL_CAMERA_RX
 132          * - bit [31] : CSIPHY2 lane 2 enable (4460+ only)
 133          * - bit [30:29] : CSIPHY2 per-lane enable (1 to 0)
 134          * - bit [28:24] : CSIPHY1 per-lane enable (4 to 0)
 135          * - bit [21] : CSIPHY2 CTRLCLK enable
 136          * - bit [20:19] : CSIPHY2 config: 00 d-phy, 01/10 ccp2
 137          * - bit [18] : CSIPHY1 CTRLCLK enable
 138          * - bit [17:16] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
 139          */
 140         /*
 141          * TODO: When implementing DT support specify the CONTROL_CAMERA_RX
 142          * register offset in the syscon property instead of hardcoding it.
 143          */
 144         regmap_read(iss->syscon, 0x68, &cam_rx_ctrl);
 145 
 146         if (subdevs->interface == ISS_INTERFACE_CSI2A_PHY1) {
 147                 cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI21_LANEENABLE_MASK |
 148                                 OMAP4_CAMERARX_CSI21_CAMMODE_MASK);
 149                 /* NOTE: Leave CSIPHY1 config to 0x0: D-PHY mode */
 150                 /* Enable all lanes for now */
 151                 cam_rx_ctrl |=
 152                         0x1f << OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT;
 153                 /* Enable CTRLCLK */
 154                 cam_rx_ctrl |= OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK;
 155         }
 156 
 157         if (subdevs->interface == ISS_INTERFACE_CSI2B_PHY2) {
 158                 cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI22_LANEENABLE_MASK |
 159                                 OMAP4_CAMERARX_CSI22_CAMMODE_MASK);
 160                 /* NOTE: Leave CSIPHY2 config to 0x0: D-PHY mode */
 161                 /* Enable all lanes for now */
 162                 cam_rx_ctrl |=
 163                         0x3 << OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT;
 164                 /* Enable CTRLCLK */
 165                 cam_rx_ctrl |= OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK;
 166         }
 167 
 168         regmap_write(iss->syscon, 0x68, cam_rx_ctrl);
 169 
 170         /* Reset used lane count */
 171         csi2->phy->used_data_lanes = 0;
 172 
 173         /* Clock and data lanes verification */
 174         for (i = 0; i < csi2->phy->max_data_lanes; i++) {
 175                 if (lanes->data[i].pos == 0)
 176                         continue;
 177 
 178                 if (lanes->data[i].pol > 1 ||
 179                     lanes->data[i].pos > (csi2->phy->max_data_lanes + 1))
 180                         return -EINVAL;
 181 
 182                 if (used_lanes & (1 << lanes->data[i].pos))
 183                         return -EINVAL;
 184 
 185                 used_lanes |= 1 << lanes->data[i].pos;
 186                 csi2->phy->used_data_lanes++;
 187         }
 188 
 189         if (lanes->clk.pol > 1 ||
 190             lanes->clk.pos > (csi2->phy->max_data_lanes + 1))
 191                 return -EINVAL;
 192 
 193         if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
 194                 return -EINVAL;
 195 
 196         csi2_ddrclk_khz = pipe->external_rate / 1000
 197                 / (2 * csi2->phy->used_data_lanes)
 198                 * pipe->external_bpp;
 199 
 200         /*
 201          * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1.
 202          * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3.
 203          */
 204         csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1;
 205         csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3;
 206         csi2phy.tclk_term = TCLK_TERM;
 207         csi2phy.tclk_miss = TCLK_MISS;
 208         csi2phy.tclk_settle = TCLK_SETTLE;
 209 
 210         mutex_lock(&csi2->phy->mutex);
 211         csi2->phy->dphy = csi2phy;
 212         csi2->phy->lanes = *lanes;
 213         mutex_unlock(&csi2->phy->mutex);
 214 
 215         return 0;
 216 }
 217 
 218 int omap4iss_csiphy_acquire(struct iss_csiphy *phy)
 219 {
 220         int rval;
 221 
 222         mutex_lock(&phy->mutex);
 223 
 224         rval = omap4iss_csi2_reset(phy->csi2);
 225         if (rval)
 226                 goto done;
 227 
 228         csiphy_dphy_config(phy);
 229         csiphy_lanes_config(phy);
 230 
 231         rval = csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_ON);
 232         if (rval)
 233                 goto done;
 234 
 235         phy->phy_in_use = 1;
 236 
 237 done:
 238         mutex_unlock(&phy->mutex);
 239         return rval;
 240 }
 241 
 242 void omap4iss_csiphy_release(struct iss_csiphy *phy)
 243 {
 244         mutex_lock(&phy->mutex);
 245         if (phy->phy_in_use) {
 246                 csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_OFF);
 247                 phy->phy_in_use = 0;
 248         }
 249         mutex_unlock(&phy->mutex);
 250 }
 251 
 252 /*
 253  * omap4iss_csiphy_init - Initialize the CSI PHY frontends
 254  */
 255 int omap4iss_csiphy_init(struct iss_device *iss)
 256 {
 257         struct iss_csiphy *phy1 = &iss->csiphy1;
 258         struct iss_csiphy *phy2 = &iss->csiphy2;
 259 
 260         phy1->iss = iss;
 261         phy1->csi2 = &iss->csi2a;
 262         phy1->max_data_lanes = ISS_CSIPHY1_NUM_DATA_LANES;
 263         phy1->used_data_lanes = 0;
 264         phy1->cfg_regs = OMAP4_ISS_MEM_CSI2_A_REGS1;
 265         phy1->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE1;
 266         mutex_init(&phy1->mutex);
 267 
 268         phy2->iss = iss;
 269         phy2->csi2 = &iss->csi2b;
 270         phy2->max_data_lanes = ISS_CSIPHY2_NUM_DATA_LANES;
 271         phy2->used_data_lanes = 0;
 272         phy2->cfg_regs = OMAP4_ISS_MEM_CSI2_B_REGS1;
 273         phy2->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE2;
 274         mutex_init(&phy2->mutex);
 275 
 276         return 0;
 277 }

/* [<][>][^][v][top][bottom][index][help] */