cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ispcsiphy.c (9725B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * ispcsiphy.c
      4 *
      5 * TI OMAP3 ISP - CSI PHY module
      6 *
      7 * Copyright (C) 2010 Nokia Corporation
      8 * Copyright (C) 2009 Texas Instruments, Inc.
      9 *
     10 * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
     11 *	     Sakari Ailus <sakari.ailus@iki.fi>
     12 */
     13
     14#include <linux/delay.h>
     15#include <linux/device.h>
     16#include <linux/regmap.h>
     17#include <linux/regulator/consumer.h>
     18
     19#include "isp.h"
     20#include "ispreg.h"
     21#include "ispcsiphy.h"
     22
     23static void csiphy_routing_cfg_3630(struct isp_csiphy *phy,
     24				    enum isp_interface_type iface,
     25				    bool ccp2_strobe)
     26{
     27	u32 reg;
     28	u32 shift, mode;
     29
     30	regmap_read(phy->isp->syscon, phy->isp->syscon_offset, &reg);
     31
     32	switch (iface) {
     33	default:
     34		/* Should not happen in practice, but let's keep the compiler happy. */
     35		return;
     36	case ISP_INTERFACE_CCP2B_PHY1:
     37		reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
     38		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
     39		break;
     40	case ISP_INTERFACE_CSI2C_PHY1:
     41		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT;
     42		mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
     43		break;
     44	case ISP_INTERFACE_CCP2B_PHY2:
     45		reg |= OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2;
     46		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
     47		break;
     48	case ISP_INTERFACE_CSI2A_PHY2:
     49		shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT;
     50		mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY;
     51		break;
     52	}
     53
     54	/* Select data/clock or data/strobe mode for CCP2 */
     55	if (iface == ISP_INTERFACE_CCP2B_PHY1 ||
     56	    iface == ISP_INTERFACE_CCP2B_PHY2) {
     57		if (ccp2_strobe)
     58			mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE;
     59		else
     60			mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_CLOCK;
     61	}
     62
     63	reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift);
     64	reg |= mode << shift;
     65
     66	regmap_write(phy->isp->syscon, phy->isp->syscon_offset, reg);
     67}
     68
     69static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on,
     70				    bool ccp2_strobe)
     71{
     72	u32 csirxfe = OMAP343X_CONTROL_CSIRXFE_PWRDNZ
     73		| OMAP343X_CONTROL_CSIRXFE_RESET;
     74
     75	/* Only the CCP2B on PHY1 is configurable. */
     76	if (iface != ISP_INTERFACE_CCP2B_PHY1)
     77		return;
     78
     79	if (!on) {
     80		regmap_write(phy->isp->syscon, phy->isp->syscon_offset, 0);
     81		return;
     82	}
     83
     84	if (ccp2_strobe)
     85		csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM;
     86
     87	regmap_write(phy->isp->syscon, phy->isp->syscon_offset, csirxfe);
     88}
     89
     90/*
     91 * Configure OMAP 3 CSI PHY routing.
     92 * @phy: relevant phy device
     93 * @iface: ISP_INTERFACE_*
     94 * @on: power on or off
     95 * @ccp2_strobe: false: data/clock, true: data/strobe
     96 *
     97 * Note that the underlying routing configuration registers are part of the
     98 * control (SCM) register space and part of the CORE power domain on both 3430
     99 * and 3630, so they will not hold their contents in off-mode. This isn't an
    100 * issue since the MPU power domain is forced on whilst the ISP is in use.
    101 */
    102static void csiphy_routing_cfg(struct isp_csiphy *phy,
    103			       enum isp_interface_type iface, bool on,
    104			       bool ccp2_strobe)
    105{
    106	if (phy->isp->phy_type == ISP_PHY_TYPE_3630 && on)
    107		return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe);
    108	if (phy->isp->phy_type == ISP_PHY_TYPE_3430)
    109		return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe);
    110}
    111
    112/*
    113 * csiphy_power_autoswitch_enable
    114 * @enable: Sets or clears the autoswitch function enable flag.
    115 */
    116static void csiphy_power_autoswitch_enable(struct isp_csiphy *phy, bool enable)
    117{
    118	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
    119			ISPCSI2_PHY_CFG_PWR_AUTO,
    120			enable ? ISPCSI2_PHY_CFG_PWR_AUTO : 0);
    121}
    122
    123/*
    124 * csiphy_set_power
    125 * @power: Power state to be set.
    126 *
    127 * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
    128 */
    129static int csiphy_set_power(struct isp_csiphy *phy, u32 power)
    130{
    131	u32 reg;
    132	u8 retry_count;
    133
    134	isp_reg_clr_set(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG,
    135			ISPCSI2_PHY_CFG_PWR_CMD_MASK, power);
    136
    137	retry_count = 0;
    138	do {
    139		udelay(50);
    140		reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG) &
    141				    ISPCSI2_PHY_CFG_PWR_STATUS_MASK;
    142
    143		if (reg != power >> 2)
    144			retry_count++;
    145
    146	} while ((reg != power >> 2) && (retry_count < 100));
    147
    148	if (retry_count == 100) {
    149		dev_err(phy->isp->dev, "CSI2 CIO set power failed!\n");
    150		return -EBUSY;
    151	}
    152
    153	return 0;
    154}
    155
    156/*
    157 * TCLK values are OK at their reset values
    158 */
    159#define TCLK_TERM	0
    160#define TCLK_MISS	1
    161#define TCLK_SETTLE	14
    162
    163static int omap3isp_csiphy_config(struct isp_csiphy *phy)
    164{
    165	struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
    166	struct isp_bus_cfg *buscfg = v4l2_subdev_to_bus_cfg(pipe->external);
    167	struct isp_csiphy_lanes_cfg *lanes;
    168	int csi2_ddrclk_khz;
    169	unsigned int num_data_lanes, used_lanes = 0;
    170	unsigned int i;
    171	u32 reg;
    172
    173	if (buscfg->interface == ISP_INTERFACE_CCP2B_PHY1
    174	    || buscfg->interface == ISP_INTERFACE_CCP2B_PHY2) {
    175		lanes = &buscfg->bus.ccp2.lanecfg;
    176		num_data_lanes = 1;
    177	} else {
    178		lanes = &buscfg->bus.csi2.lanecfg;
    179		num_data_lanes = buscfg->bus.csi2.num_data_lanes;
    180	}
    181
    182	if (num_data_lanes > phy->num_data_lanes)
    183		return -EINVAL;
    184
    185	/* Clock and data lanes verification */
    186	for (i = 0; i < num_data_lanes; i++) {
    187		if (lanes->data[i].pol > 1 || lanes->data[i].pos > 3)
    188			return -EINVAL;
    189
    190		if (used_lanes & (1 << lanes->data[i].pos))
    191			return -EINVAL;
    192
    193		used_lanes |= 1 << lanes->data[i].pos;
    194	}
    195
    196	if (lanes->clk.pol > 1 || lanes->clk.pos > 3)
    197		return -EINVAL;
    198
    199	if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
    200		return -EINVAL;
    201
    202	/*
    203	 * The PHY configuration is lost in off mode, that's not an
    204	 * issue since the MPU power domain is forced on whilst the
    205	 * ISP is in use.
    206	 */
    207	csiphy_routing_cfg(phy, buscfg->interface, true,
    208			   buscfg->bus.ccp2.phy_layer);
    209
    210	/* DPHY timing configuration */
    211	/* CSI-2 is DDR and we only count used lanes. */
    212	csi2_ddrclk_khz = pipe->external_rate / 1000
    213		/ (2 * hweight32(used_lanes)) * pipe->external_width;
    214
    215	reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0);
    216
    217	reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK |
    218		 ISPCSIPHY_REG0_THS_SETTLE_MASK);
    219	/* THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. */
    220	reg |= (DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1)
    221		<< ISPCSIPHY_REG0_THS_TERM_SHIFT;
    222	/* THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. */
    223	reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3)
    224		<< ISPCSIPHY_REG0_THS_SETTLE_SHIFT;
    225
    226	isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0);
    227
    228	reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1);
    229
    230	reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK |
    231		 ISPCSIPHY_REG1_TCLK_MISS_MASK |
    232		 ISPCSIPHY_REG1_TCLK_SETTLE_MASK);
    233	reg |= TCLK_TERM << ISPCSIPHY_REG1_TCLK_TERM_SHIFT;
    234	reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT;
    235	reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT;
    236
    237	isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1);
    238
    239	/* DPHY lane configuration */
    240	reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG);
    241
    242	for (i = 0; i < num_data_lanes; i++) {
    243		reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) |
    244			 ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1));
    245		reg |= (lanes->data[i].pol <<
    246			ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1));
    247		reg |= (lanes->data[i].pos <<
    248			ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1));
    249	}
    250
    251	reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK |
    252		 ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK);
    253	reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT;
    254	reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT;
    255
    256	isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG);
    257
    258	return 0;
    259}
    260
    261int omap3isp_csiphy_acquire(struct isp_csiphy *phy, struct media_entity *entity)
    262{
    263	int rval;
    264
    265	if (phy->vdd == NULL) {
    266		dev_err(phy->isp->dev,
    267			"Power regulator for CSI PHY not available\n");
    268		return -ENODEV;
    269	}
    270
    271	mutex_lock(&phy->mutex);
    272
    273	rval = regulator_enable(phy->vdd);
    274	if (rval < 0)
    275		goto done;
    276
    277	rval = omap3isp_csi2_reset(phy->csi2);
    278	if (rval < 0)
    279		goto done;
    280
    281	phy->entity = entity;
    282
    283	rval = omap3isp_csiphy_config(phy);
    284	if (rval < 0)
    285		goto done;
    286
    287	if (phy->isp->revision == ISP_REVISION_15_0) {
    288		rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON);
    289		if (rval) {
    290			regulator_disable(phy->vdd);
    291			goto done;
    292		}
    293
    294		csiphy_power_autoswitch_enable(phy, true);
    295	}
    296done:
    297	if (rval < 0)
    298		phy->entity = NULL;
    299
    300	mutex_unlock(&phy->mutex);
    301	return rval;
    302}
    303
    304void omap3isp_csiphy_release(struct isp_csiphy *phy)
    305{
    306	mutex_lock(&phy->mutex);
    307	if (phy->entity) {
    308		struct isp_pipeline *pipe = to_isp_pipeline(phy->entity);
    309		struct isp_bus_cfg *buscfg =
    310			v4l2_subdev_to_bus_cfg(pipe->external);
    311
    312		csiphy_routing_cfg(phy, buscfg->interface, false,
    313				   buscfg->bus.ccp2.phy_layer);
    314		if (phy->isp->revision == ISP_REVISION_15_0) {
    315			csiphy_power_autoswitch_enable(phy, false);
    316			csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF);
    317		}
    318		regulator_disable(phy->vdd);
    319		phy->entity = NULL;
    320	}
    321	mutex_unlock(&phy->mutex);
    322}
    323
    324/*
    325 * omap3isp_csiphy_init - Initialize the CSI PHY frontends
    326 */
    327int omap3isp_csiphy_init(struct isp_device *isp)
    328{
    329	struct isp_csiphy *phy1 = &isp->isp_csiphy1;
    330	struct isp_csiphy *phy2 = &isp->isp_csiphy2;
    331
    332	phy2->isp = isp;
    333	phy2->csi2 = &isp->isp_csi2a;
    334	phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES;
    335	phy2->cfg_regs = OMAP3_ISP_IOMEM_CSI2A_REGS1;
    336	phy2->phy_regs = OMAP3_ISP_IOMEM_CSIPHY2;
    337	mutex_init(&phy2->mutex);
    338
    339	phy1->isp = isp;
    340	mutex_init(&phy1->mutex);
    341
    342	if (isp->revision == ISP_REVISION_15_0) {
    343		phy1->csi2 = &isp->isp_csi2c;
    344		phy1->num_data_lanes = ISP_CSIPHY1_NUM_DATA_LANES;
    345		phy1->cfg_regs = OMAP3_ISP_IOMEM_CSI2C_REGS1;
    346		phy1->phy_regs = OMAP3_ISP_IOMEM_CSIPHY1;
    347	}
    348
    349	return 0;
    350}
    351
    352void omap3isp_csiphy_cleanup(struct isp_device *isp)
    353{
    354	mutex_destroy(&isp->isp_csiphy1.mutex);
    355	mutex_destroy(&isp->isp_csiphy2.mutex);
    356}