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

cal-camerarx.c (25984B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TI Camera Access Layer (CAL) - CAMERARX
      4 *
      5 * Copyright (c) 2015-2020 Texas Instruments Inc.
      6 *
      7 * Authors:
      8 *	Benoit Parrot <bparrot@ti.com>
      9 *	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
     10 */
     11
     12#include <linux/clk.h>
     13#include <linux/delay.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/module.h>
     16#include <linux/of_graph.h>
     17#include <linux/platform_device.h>
     18#include <linux/regmap.h>
     19#include <linux/slab.h>
     20
     21#include <media/v4l2-ctrls.h>
     22#include <media/v4l2-fwnode.h>
     23#include <media/v4l2-subdev.h>
     24
     25#include "cal.h"
     26#include "cal_regs.h"
     27
     28/* ------------------------------------------------------------------
     29 *	I/O Register Accessors
     30 * ------------------------------------------------------------------
     31 */
     32
     33static inline u32 camerarx_read(struct cal_camerarx *phy, u32 offset)
     34{
     35	return ioread32(phy->base + offset);
     36}
     37
     38static inline void camerarx_write(struct cal_camerarx *phy, u32 offset, u32 val)
     39{
     40	iowrite32(val, phy->base + offset);
     41}
     42
     43/* ------------------------------------------------------------------
     44 *	CAMERARX Management
     45 * ------------------------------------------------------------------
     46 */
     47
     48static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy)
     49{
     50	struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2;
     51	u32 num_lanes = mipi_csi2->num_data_lanes;
     52	const struct cal_format_info *fmtinfo;
     53	u32 bpp;
     54	s64 freq;
     55
     56	fmtinfo = cal_format_by_code(phy->formats[CAL_CAMERARX_PAD_SINK].code);
     57	if (!fmtinfo)
     58		return -EINVAL;
     59
     60	bpp = fmtinfo->bpp;
     61
     62	freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes);
     63	if (freq < 0) {
     64		phy_err(phy, "failed to get link freq for subdev '%s'\n",
     65			phy->source->name);
     66		return freq;
     67	}
     68
     69	phy_dbg(3, phy, "Source Link Freq: %llu\n", freq);
     70
     71	return freq;
     72}
     73
     74static void cal_camerarx_lane_config(struct cal_camerarx *phy)
     75{
     76	u32 val = cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance));
     77	u32 lane_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK;
     78	u32 polarity_mask = CAL_CSI2_COMPLEXIO_CFG_CLOCK_POL_MASK;
     79	struct v4l2_mbus_config_mipi_csi2 *mipi_csi2 =
     80		&phy->endpoint.bus.mipi_csi2;
     81	int lane;
     82
     83	cal_set_field(&val, mipi_csi2->clock_lane + 1, lane_mask);
     84	cal_set_field(&val, mipi_csi2->lane_polarities[0], polarity_mask);
     85	for (lane = 0; lane < mipi_csi2->num_data_lanes; lane++) {
     86		/*
     87		 * Every lane are one nibble apart starting with the
     88		 * clock followed by the data lanes so shift masks by 4.
     89		 */
     90		lane_mask <<= 4;
     91		polarity_mask <<= 4;
     92		cal_set_field(&val, mipi_csi2->data_lanes[lane] + 1, lane_mask);
     93		cal_set_field(&val, mipi_csi2->lane_polarities[lane + 1],
     94			      polarity_mask);
     95	}
     96
     97	cal_write(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance), val);
     98	phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x\n",
     99		phy->instance, val);
    100}
    101
    102static void cal_camerarx_enable(struct cal_camerarx *phy)
    103{
    104	u32 num_lanes = phy->cal->data->camerarx[phy->instance].num_lanes;
    105
    106	regmap_field_write(phy->fields[F_CAMMODE], 0);
    107	/* Always enable all lanes at the phy control level */
    108	regmap_field_write(phy->fields[F_LANEENABLE], (1 << num_lanes) - 1);
    109	/* F_CSI_MODE is not present on every architecture */
    110	if (phy->fields[F_CSI_MODE])
    111		regmap_field_write(phy->fields[F_CSI_MODE], 1);
    112	regmap_field_write(phy->fields[F_CTRLCLKEN], 1);
    113}
    114
    115void cal_camerarx_disable(struct cal_camerarx *phy)
    116{
    117	regmap_field_write(phy->fields[F_CTRLCLKEN], 0);
    118}
    119
    120/*
    121 * TCLK values are OK at their reset values
    122 */
    123#define TCLK_TERM	0
    124#define TCLK_MISS	1
    125#define TCLK_SETTLE	14
    126
    127static void cal_camerarx_config(struct cal_camerarx *phy, s64 link_freq)
    128{
    129	unsigned int reg0, reg1;
    130	unsigned int ths_term, ths_settle;
    131
    132	/* DPHY timing configuration */
    133
    134	/* THS_TERM: Programmed value = floor(20 ns/DDRClk period) */
    135	ths_term = div_s64(20 * link_freq, 1000 * 1000 * 1000);
    136	phy_dbg(1, phy, "ths_term: %d (0x%02x)\n", ths_term, ths_term);
    137
    138	/* THS_SETTLE: Programmed value = floor(105 ns/DDRClk period) + 4 */
    139	ths_settle = div_s64(105 * link_freq, 1000 * 1000 * 1000) + 4;
    140	phy_dbg(1, phy, "ths_settle: %d (0x%02x)\n", ths_settle, ths_settle);
    141
    142	reg0 = camerarx_read(phy, CAL_CSI2_PHY_REG0);
    143	cal_set_field(&reg0, CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_DISABLE,
    144		      CAL_CSI2_PHY_REG0_HSCLOCKCONFIG_MASK);
    145	cal_set_field(&reg0, ths_term, CAL_CSI2_PHY_REG0_THS_TERM_MASK);
    146	cal_set_field(&reg0, ths_settle, CAL_CSI2_PHY_REG0_THS_SETTLE_MASK);
    147
    148	phy_dbg(1, phy, "CSI2_%d_REG0 = 0x%08x\n", phy->instance, reg0);
    149	camerarx_write(phy, CAL_CSI2_PHY_REG0, reg0);
    150
    151	reg1 = camerarx_read(phy, CAL_CSI2_PHY_REG1);
    152	cal_set_field(&reg1, TCLK_TERM, CAL_CSI2_PHY_REG1_TCLK_TERM_MASK);
    153	cal_set_field(&reg1, 0xb8, CAL_CSI2_PHY_REG1_DPHY_HS_SYNC_PATTERN_MASK);
    154	cal_set_field(&reg1, TCLK_MISS,
    155		      CAL_CSI2_PHY_REG1_CTRLCLK_DIV_FACTOR_MASK);
    156	cal_set_field(&reg1, TCLK_SETTLE, CAL_CSI2_PHY_REG1_TCLK_SETTLE_MASK);
    157
    158	phy_dbg(1, phy, "CSI2_%d_REG1 = 0x%08x\n", phy->instance, reg1);
    159	camerarx_write(phy, CAL_CSI2_PHY_REG1, reg1);
    160}
    161
    162static void cal_camerarx_power(struct cal_camerarx *phy, bool enable)
    163{
    164	u32 target_state;
    165	unsigned int i;
    166
    167	target_state = enable ? CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_ON :
    168		       CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_STATE_OFF;
    169
    170	cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    171			target_state, CAL_CSI2_COMPLEXIO_CFG_PWR_CMD_MASK);
    172
    173	for (i = 0; i < 10; i++) {
    174		u32 current_state;
    175
    176		current_state = cal_read_field(phy->cal,
    177					       CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    178					       CAL_CSI2_COMPLEXIO_CFG_PWR_STATUS_MASK);
    179
    180		if (current_state == target_state)
    181			break;
    182
    183		usleep_range(1000, 1100);
    184	}
    185
    186	if (i == 10)
    187		phy_err(phy, "Failed to power %s complexio\n",
    188			enable ? "up" : "down");
    189}
    190
    191static void cal_camerarx_wait_reset(struct cal_camerarx *phy)
    192{
    193	unsigned long timeout;
    194
    195	timeout = jiffies + msecs_to_jiffies(750);
    196	while (time_before(jiffies, timeout)) {
    197		if (cal_read_field(phy->cal,
    198				   CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    199				   CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) ==
    200		    CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED)
    201			break;
    202		usleep_range(500, 5000);
    203	}
    204
    205	if (cal_read_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    206			   CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_MASK) !=
    207			   CAL_CSI2_COMPLEXIO_CFG_RESET_DONE_RESETCOMPLETED)
    208		phy_err(phy, "Timeout waiting for Complex IO reset done\n");
    209}
    210
    211static void cal_camerarx_wait_stop_state(struct cal_camerarx *phy)
    212{
    213	unsigned long timeout;
    214
    215	timeout = jiffies + msecs_to_jiffies(750);
    216	while (time_before(jiffies, timeout)) {
    217		if (cal_read_field(phy->cal,
    218				   CAL_CSI2_TIMING(phy->instance),
    219				   CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) == 0)
    220			break;
    221		usleep_range(500, 5000);
    222	}
    223
    224	if (cal_read_field(phy->cal, CAL_CSI2_TIMING(phy->instance),
    225			   CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK) != 0)
    226		phy_err(phy, "Timeout waiting for stop state\n");
    227}
    228
    229static void cal_camerarx_enable_irqs(struct cal_camerarx *phy)
    230{
    231	const u32 cio_err_mask =
    232		CAL_CSI2_COMPLEXIO_IRQ_LANE_ERRORS_MASK |
    233		CAL_CSI2_COMPLEXIO_IRQ_FIFO_OVR_MASK |
    234		CAL_CSI2_COMPLEXIO_IRQ_SHORT_PACKET_MASK |
    235		CAL_CSI2_COMPLEXIO_IRQ_ECC_NO_CORRECTION_MASK;
    236	const u32 vc_err_mask =
    237		CAL_CSI2_VC_IRQ_CS_IRQ_MASK(0) |
    238		CAL_CSI2_VC_IRQ_CS_IRQ_MASK(1) |
    239		CAL_CSI2_VC_IRQ_CS_IRQ_MASK(2) |
    240		CAL_CSI2_VC_IRQ_CS_IRQ_MASK(3) |
    241		CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(0) |
    242		CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(1) |
    243		CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(2) |
    244		CAL_CSI2_VC_IRQ_ECC_CORRECTION_IRQ_MASK(3);
    245
    246	/* Enable CIO & VC error IRQs. */
    247	cal_write(phy->cal, CAL_HL_IRQENABLE_SET(0),
    248		  CAL_HL_IRQ_CIO_MASK(phy->instance) |
    249		  CAL_HL_IRQ_VC_MASK(phy->instance));
    250	cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance),
    251		  cio_err_mask);
    252	cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance),
    253		  vc_err_mask);
    254}
    255
    256static void cal_camerarx_disable_irqs(struct cal_camerarx *phy)
    257{
    258	/* Disable CIO error irqs */
    259	cal_write(phy->cal, CAL_HL_IRQENABLE_CLR(0),
    260		  CAL_HL_IRQ_CIO_MASK(phy->instance) |
    261		  CAL_HL_IRQ_VC_MASK(phy->instance));
    262	cal_write(phy->cal, CAL_CSI2_COMPLEXIO_IRQENABLE(phy->instance), 0);
    263	cal_write(phy->cal, CAL_CSI2_VC_IRQENABLE(phy->instance), 0);
    264}
    265
    266static void cal_camerarx_ppi_enable(struct cal_camerarx *phy)
    267{
    268	cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance),
    269			1, CAL_CSI2_PPI_CTRL_ECC_EN_MASK);
    270
    271	cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance),
    272			1, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
    273}
    274
    275static void cal_camerarx_ppi_disable(struct cal_camerarx *phy)
    276{
    277	cal_write_field(phy->cal, CAL_CSI2_PPI_CTRL(phy->instance),
    278			0, CAL_CSI2_PPI_CTRL_IF_EN_MASK);
    279}
    280
    281static int cal_camerarx_start(struct cal_camerarx *phy)
    282{
    283	s64 link_freq;
    284	u32 sscounter;
    285	u32 val;
    286	int ret;
    287
    288	if (phy->enable_count > 0) {
    289		phy->enable_count++;
    290		return 0;
    291	}
    292
    293	link_freq = cal_camerarx_get_ext_link_freq(phy);
    294	if (link_freq < 0)
    295		return link_freq;
    296
    297	ret = v4l2_subdev_call(phy->source, core, s_power, 1);
    298	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) {
    299		phy_err(phy, "power on failed in subdev\n");
    300		return ret;
    301	}
    302
    303	cal_camerarx_enable_irqs(phy);
    304
    305	/*
    306	 * CSI-2 PHY Link Initialization Sequence, according to the DRA74xP /
    307	 * DRA75xP / DRA76xP / DRA77xP TRM. The DRA71x / DRA72x and the AM65x /
    308	 * DRA80xM TRMs have a a slightly simplified sequence.
    309	 */
    310
    311	/*
    312	 * 1. Configure all CSI-2 low level protocol registers to be ready to
    313	 *    receive signals/data from the CSI-2 PHY.
    314	 *
    315	 *    i.-v. Configure the lanes position and polarity.
    316	 */
    317	cal_camerarx_lane_config(phy);
    318
    319	/*
    320	 *    vi.-vii. Configure D-PHY mode, enable the required lanes and
    321	 *             enable the CAMERARX clock.
    322	 */
    323	cal_camerarx_enable(phy);
    324
    325	/*
    326	 * 2. CSI PHY and link initialization sequence.
    327	 *
    328	 *    a. Deassert the CSI-2 PHY reset. Do not wait for reset completion
    329	 *       at this point, as it requires the external source to send the
    330	 *       CSI-2 HS clock.
    331	 */
    332	cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    333			CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_OPERATIONAL,
    334			CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
    335	phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x De-assert Complex IO Reset\n",
    336		phy->instance,
    337		cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)));
    338
    339	/* Dummy read to allow SCP reset to complete. */
    340	camerarx_read(phy, CAL_CSI2_PHY_REG0);
    341
    342	/* Program the PHY timing parameters. */
    343	cal_camerarx_config(phy, link_freq);
    344
    345	/*
    346	 *    b. Assert the FORCERXMODE signal.
    347	 *
    348	 * The stop-state-counter is based on fclk cycles, and we always use
    349	 * the x16 and x4 settings, so stop-state-timeout =
    350	 * fclk-cycle * 16 * 4 * counter.
    351	 *
    352	 * Stop-state-timeout must be more than 100us as per CSI-2 spec, so we
    353	 * calculate a timeout that's 100us (rounding up).
    354	 */
    355	sscounter = DIV_ROUND_UP(clk_get_rate(phy->cal->fclk), 10000 *  16 * 4);
    356
    357	val = cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance));
    358	cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X16_IO1_MASK);
    359	cal_set_field(&val, 1, CAL_CSI2_TIMING_STOP_STATE_X4_IO1_MASK);
    360	cal_set_field(&val, sscounter,
    361		      CAL_CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK);
    362	cal_write(phy->cal, CAL_CSI2_TIMING(phy->instance), val);
    363	phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Stop States\n",
    364		phy->instance,
    365		cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance)));
    366
    367	/* Assert the FORCERXMODE signal. */
    368	cal_write_field(phy->cal, CAL_CSI2_TIMING(phy->instance),
    369			1, CAL_CSI2_TIMING_FORCE_RX_MODE_IO1_MASK);
    370	phy_dbg(3, phy, "CAL_CSI2_TIMING(%d) = 0x%08x Force RXMODE\n",
    371		phy->instance,
    372		cal_read(phy->cal, CAL_CSI2_TIMING(phy->instance)));
    373
    374	/*
    375	 * c. Connect pull-down on CSI-2 PHY link (using pad control).
    376	 *
    377	 * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not
    378	 * implemented.
    379	 */
    380
    381	/*
    382	 * d. Power up the CSI-2 PHY.
    383	 * e. Check whether the state status reaches the ON state.
    384	 */
    385	cal_camerarx_power(phy, true);
    386
    387	/*
    388	 * Start the source to enable the CSI-2 HS clock. We can now wait for
    389	 * CSI-2 PHY reset to complete.
    390	 */
    391	ret = v4l2_subdev_call(phy->source, video, s_stream, 1);
    392	if (ret) {
    393		v4l2_subdev_call(phy->source, core, s_power, 0);
    394		cal_camerarx_disable_irqs(phy);
    395		phy_err(phy, "stream on failed in subdev\n");
    396		return ret;
    397	}
    398
    399	cal_camerarx_wait_reset(phy);
    400
    401	/* f. Wait for STOPSTATE=1 for all enabled lane modules. */
    402	cal_camerarx_wait_stop_state(phy);
    403
    404	phy_dbg(1, phy, "CSI2_%u_REG1 = 0x%08x (bits 31-28 should be set)\n",
    405		phy->instance, camerarx_read(phy, CAL_CSI2_PHY_REG1));
    406
    407	/*
    408	 * g. Disable pull-down on CSI-2 PHY link (using pad control).
    409	 *
    410	 * This is not required on DRA71x, DRA72x, AM65x and DRA80xM. Not
    411	 * implemented.
    412	 */
    413
    414	/* Finally, enable the PHY Protocol Interface (PPI). */
    415	cal_camerarx_ppi_enable(phy);
    416
    417	phy->enable_count++;
    418
    419	return 0;
    420}
    421
    422static void cal_camerarx_stop(struct cal_camerarx *phy)
    423{
    424	int ret;
    425
    426	if (--phy->enable_count > 0)
    427		return;
    428
    429	cal_camerarx_ppi_disable(phy);
    430
    431	cal_camerarx_disable_irqs(phy);
    432
    433	cal_camerarx_power(phy, false);
    434
    435	/* Assert Complex IO Reset */
    436	cal_write_field(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance),
    437			CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL,
    438			CAL_CSI2_COMPLEXIO_CFG_RESET_CTRL_MASK);
    439
    440	phy_dbg(3, phy, "CAL_CSI2_COMPLEXIO_CFG(%d) = 0x%08x Complex IO in Reset\n",
    441		phy->instance,
    442		cal_read(phy->cal, CAL_CSI2_COMPLEXIO_CFG(phy->instance)));
    443
    444	/* Disable the phy */
    445	cal_camerarx_disable(phy);
    446
    447	if (v4l2_subdev_call(phy->source, video, s_stream, 0))
    448		phy_err(phy, "stream off failed in subdev\n");
    449
    450	ret = v4l2_subdev_call(phy->source, core, s_power, 0);
    451	if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV)
    452		phy_err(phy, "power off failed in subdev\n");
    453}
    454
    455/*
    456 *   Errata i913: CSI2 LDO Needs to be disabled when module is powered on
    457 *
    458 *   Enabling CSI2 LDO shorts it to core supply. It is crucial the 2 CSI2
    459 *   LDOs on the device are disabled if CSI-2 module is powered on
    460 *   (0x4845 B304 | 0x4845 B384 [28:27] = 0x1) or in ULPS (0x4845 B304
    461 *   | 0x4845 B384 [28:27] = 0x2) mode. Common concerns include: high
    462 *   current draw on the module supply in active mode.
    463 *
    464 *   Errata does not apply when CSI-2 module is powered off
    465 *   (0x4845 B304 | 0x4845 B384 [28:27] = 0x0).
    466 *
    467 * SW Workaround:
    468 *	Set the following register bits to disable the LDO,
    469 *	which is essentially CSI2 REG10 bit 6:
    470 *
    471 *		Core 0:  0x4845 B828 = 0x0000 0040
    472 *		Core 1:  0x4845 B928 = 0x0000 0040
    473 */
    474void cal_camerarx_i913_errata(struct cal_camerarx *phy)
    475{
    476	u32 reg10 = camerarx_read(phy, CAL_CSI2_PHY_REG10);
    477
    478	cal_set_field(&reg10, 1, CAL_CSI2_PHY_REG10_I933_LDO_DISABLE_MASK);
    479
    480	phy_dbg(1, phy, "CSI2_%d_REG10 = 0x%08x\n", phy->instance, reg10);
    481	camerarx_write(phy, CAL_CSI2_PHY_REG10, reg10);
    482}
    483
    484static int cal_camerarx_regmap_init(struct cal_dev *cal,
    485				    struct cal_camerarx *phy)
    486{
    487	const struct cal_camerarx_data *phy_data;
    488	unsigned int i;
    489
    490	if (!cal->data)
    491		return -EINVAL;
    492
    493	phy_data = &cal->data->camerarx[phy->instance];
    494
    495	for (i = 0; i < F_MAX_FIELDS; i++) {
    496		struct reg_field field = {
    497			.reg = cal->syscon_camerrx_offset,
    498			.lsb = phy_data->fields[i].lsb,
    499			.msb = phy_data->fields[i].msb,
    500		};
    501
    502		/*
    503		 * Here we update the reg offset with the
    504		 * value found in DT
    505		 */
    506		phy->fields[i] = devm_regmap_field_alloc(cal->dev,
    507							 cal->syscon_camerrx,
    508							 field);
    509		if (IS_ERR(phy->fields[i])) {
    510			cal_err(cal, "Unable to allocate regmap fields\n");
    511			return PTR_ERR(phy->fields[i]);
    512		}
    513	}
    514
    515	return 0;
    516}
    517
    518static int cal_camerarx_parse_dt(struct cal_camerarx *phy)
    519{
    520	struct v4l2_fwnode_endpoint *endpoint = &phy->endpoint;
    521	char data_lanes[V4L2_MBUS_CSI2_MAX_DATA_LANES * 2];
    522	struct device_node *ep_node;
    523	unsigned int i;
    524	int ret;
    525
    526	/*
    527	 * Find the endpoint node for the port corresponding to the PHY
    528	 * instance, and parse its CSI-2-related properties.
    529	 */
    530	ep_node = of_graph_get_endpoint_by_regs(phy->cal->dev->of_node,
    531						phy->instance, 0);
    532	if (!ep_node) {
    533		/*
    534		 * The endpoint is not mandatory, not all PHY instances need to
    535		 * be connected in DT.
    536		 */
    537		phy_dbg(3, phy, "Port has no endpoint\n");
    538		return 0;
    539	}
    540
    541	endpoint->bus_type = V4L2_MBUS_CSI2_DPHY;
    542	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint);
    543	if (ret < 0) {
    544		phy_err(phy, "Failed to parse endpoint\n");
    545		goto done;
    546	}
    547
    548	for (i = 0; i < endpoint->bus.mipi_csi2.num_data_lanes; i++) {
    549		unsigned int lane = endpoint->bus.mipi_csi2.data_lanes[i];
    550
    551		if (lane > 4) {
    552			phy_err(phy, "Invalid position %u for data lane %u\n",
    553				lane, i);
    554			ret = -EINVAL;
    555			goto done;
    556		}
    557
    558		data_lanes[i*2] = '0' + lane;
    559		data_lanes[i*2+1] = ' ';
    560	}
    561
    562	data_lanes[i*2-1] = '\0';
    563
    564	phy_dbg(3, phy,
    565		"CSI-2 bus: clock lane <%u>, data lanes <%s>, flags 0x%08x\n",
    566		endpoint->bus.mipi_csi2.clock_lane, data_lanes,
    567		endpoint->bus.mipi_csi2.flags);
    568
    569	/* Retrieve the connected device and store it for later use. */
    570	phy->source_ep_node = of_graph_get_remote_endpoint(ep_node);
    571	phy->source_node = of_graph_get_port_parent(phy->source_ep_node);
    572	if (!phy->source_node) {
    573		phy_dbg(3, phy, "Can't get remote parent\n");
    574		of_node_put(phy->source_ep_node);
    575		ret = -EINVAL;
    576		goto done;
    577	}
    578
    579	phy_dbg(1, phy, "Found connected device %pOFn\n", phy->source_node);
    580
    581done:
    582	of_node_put(ep_node);
    583	return ret;
    584}
    585
    586int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy,
    587				       struct v4l2_mbus_frame_desc *desc)
    588{
    589	struct media_pad *pad;
    590	int ret;
    591
    592	if (!phy->source)
    593		return -EPIPE;
    594
    595	pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]);
    596	if (!pad)
    597		return -EPIPE;
    598
    599	ret = v4l2_subdev_call(phy->source, pad, get_frame_desc, pad->index,
    600			       desc);
    601	if (ret)
    602		return ret;
    603
    604	if (desc->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
    605		dev_err(phy->cal->dev,
    606			"Frame descriptor does not describe CSI-2 link");
    607		return -EINVAL;
    608	}
    609
    610	return 0;
    611}
    612
    613/* ------------------------------------------------------------------
    614 *	V4L2 Subdev Operations
    615 * ------------------------------------------------------------------
    616 */
    617
    618static inline struct cal_camerarx *to_cal_camerarx(struct v4l2_subdev *sd)
    619{
    620	return container_of(sd, struct cal_camerarx, subdev);
    621}
    622
    623static struct v4l2_mbus_framefmt *
    624cal_camerarx_get_pad_format(struct cal_camerarx *phy,
    625			    struct v4l2_subdev_state *sd_state,
    626			    unsigned int pad, u32 which)
    627{
    628	switch (which) {
    629	case V4L2_SUBDEV_FORMAT_TRY:
    630		return v4l2_subdev_get_try_format(&phy->subdev, sd_state, pad);
    631	case V4L2_SUBDEV_FORMAT_ACTIVE:
    632		return &phy->formats[pad];
    633	default:
    634		return NULL;
    635	}
    636}
    637
    638static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
    639{
    640	struct cal_camerarx *phy = to_cal_camerarx(sd);
    641	int ret = 0;
    642
    643	mutex_lock(&phy->mutex);
    644
    645	if (enable)
    646		ret = cal_camerarx_start(phy);
    647	else
    648		cal_camerarx_stop(phy);
    649
    650	mutex_unlock(&phy->mutex);
    651
    652	return ret;
    653}
    654
    655static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
    656					  struct v4l2_subdev_state *sd_state,
    657					  struct v4l2_subdev_mbus_code_enum *code)
    658{
    659	struct cal_camerarx *phy = to_cal_camerarx(sd);
    660	int ret = 0;
    661
    662	mutex_lock(&phy->mutex);
    663
    664	/* No transcoding, source and sink codes must match. */
    665	if (cal_rx_pad_is_source(code->pad)) {
    666		struct v4l2_mbus_framefmt *fmt;
    667
    668		if (code->index > 0) {
    669			ret = -EINVAL;
    670			goto out;
    671		}
    672
    673		fmt = cal_camerarx_get_pad_format(phy, sd_state,
    674						  CAL_CAMERARX_PAD_SINK,
    675						  code->which);
    676		code->code = fmt->code;
    677	} else {
    678		if (code->index >= cal_num_formats) {
    679			ret = -EINVAL;
    680			goto out;
    681		}
    682
    683		code->code = cal_formats[code->index].code;
    684	}
    685
    686out:
    687	mutex_unlock(&phy->mutex);
    688
    689	return ret;
    690}
    691
    692static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
    693					   struct v4l2_subdev_state *sd_state,
    694					   struct v4l2_subdev_frame_size_enum *fse)
    695{
    696	struct cal_camerarx *phy = to_cal_camerarx(sd);
    697	const struct cal_format_info *fmtinfo;
    698	int ret = 0;
    699
    700	if (fse->index > 0)
    701		return -EINVAL;
    702
    703	mutex_lock(&phy->mutex);
    704
    705	/* No transcoding, source and sink formats must match. */
    706	if (cal_rx_pad_is_source(fse->pad)) {
    707		struct v4l2_mbus_framefmt *fmt;
    708
    709		fmt = cal_camerarx_get_pad_format(phy, sd_state,
    710						  CAL_CAMERARX_PAD_SINK,
    711						  fse->which);
    712		if (fse->code != fmt->code) {
    713			ret = -EINVAL;
    714			goto out;
    715		}
    716
    717		fse->min_width = fmt->width;
    718		fse->max_width = fmt->width;
    719		fse->min_height = fmt->height;
    720		fse->max_height = fmt->height;
    721	} else {
    722		fmtinfo = cal_format_by_code(fse->code);
    723		if (!fmtinfo) {
    724			ret = -EINVAL;
    725			goto out;
    726		}
    727
    728		fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
    729		fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
    730		fse->min_height = CAL_MIN_HEIGHT_LINES;
    731		fse->max_height = CAL_MAX_HEIGHT_LINES;
    732	}
    733
    734out:
    735	mutex_unlock(&phy->mutex);
    736
    737	return ret;
    738}
    739
    740static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
    741				   struct v4l2_subdev_state *sd_state,
    742				   struct v4l2_subdev_format *format)
    743{
    744	struct cal_camerarx *phy = to_cal_camerarx(sd);
    745	struct v4l2_mbus_framefmt *fmt;
    746
    747	mutex_lock(&phy->mutex);
    748
    749	fmt = cal_camerarx_get_pad_format(phy, sd_state, format->pad,
    750					  format->which);
    751	format->format = *fmt;
    752
    753	mutex_unlock(&phy->mutex);
    754
    755	return 0;
    756}
    757
    758static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
    759				   struct v4l2_subdev_state *sd_state,
    760				   struct v4l2_subdev_format *format)
    761{
    762	struct cal_camerarx *phy = to_cal_camerarx(sd);
    763	const struct cal_format_info *fmtinfo;
    764	struct v4l2_mbus_framefmt *fmt;
    765	unsigned int bpp;
    766
    767	/* No transcoding, source and sink formats must match. */
    768	if (cal_rx_pad_is_source(format->pad))
    769		return cal_camerarx_sd_get_fmt(sd, sd_state, format);
    770
    771	/*
    772	 * Default to the first format if the requested media bus code isn't
    773	 * supported.
    774	 */
    775	fmtinfo = cal_format_by_code(format->format.code);
    776	if (!fmtinfo)
    777		fmtinfo = &cal_formats[0];
    778
    779	/* Clamp the size, update the code. The colorspace is accepted as-is. */
    780	bpp = ALIGN(fmtinfo->bpp, 8);
    781
    782	format->format.width = clamp_t(unsigned int, format->format.width,
    783				       CAL_MIN_WIDTH_BYTES * 8 / bpp,
    784				       CAL_MAX_WIDTH_BYTES * 8 / bpp);
    785	format->format.height = clamp_t(unsigned int, format->format.height,
    786					CAL_MIN_HEIGHT_LINES,
    787					CAL_MAX_HEIGHT_LINES);
    788	format->format.code = fmtinfo->code;
    789	format->format.field = V4L2_FIELD_NONE;
    790
    791	/* Store the format and propagate it to the source pad. */
    792
    793	mutex_lock(&phy->mutex);
    794
    795	fmt = cal_camerarx_get_pad_format(phy, sd_state,
    796					  CAL_CAMERARX_PAD_SINK,
    797					  format->which);
    798	*fmt = format->format;
    799
    800	fmt = cal_camerarx_get_pad_format(phy, sd_state,
    801					  CAL_CAMERARX_PAD_FIRST_SOURCE,
    802					  format->which);
    803	*fmt = format->format;
    804
    805	mutex_unlock(&phy->mutex);
    806
    807	return 0;
    808}
    809
    810static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
    811				    struct v4l2_subdev_state *sd_state)
    812{
    813	struct v4l2_subdev_format format = {
    814		.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
    815		: V4L2_SUBDEV_FORMAT_ACTIVE,
    816		.pad = CAL_CAMERARX_PAD_SINK,
    817		.format = {
    818			.width = 640,
    819			.height = 480,
    820			.code = MEDIA_BUS_FMT_UYVY8_2X8,
    821			.field = V4L2_FIELD_NONE,
    822			.colorspace = V4L2_COLORSPACE_SRGB,
    823			.ycbcr_enc = V4L2_YCBCR_ENC_601,
    824			.quantization = V4L2_QUANTIZATION_LIM_RANGE,
    825			.xfer_func = V4L2_XFER_FUNC_SRGB,
    826		},
    827	};
    828
    829	return cal_camerarx_sd_set_fmt(sd, sd_state, &format);
    830}
    831
    832static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
    833	.s_stream = cal_camerarx_sd_s_stream,
    834};
    835
    836static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = {
    837	.init_cfg = cal_camerarx_sd_init_cfg,
    838	.enum_mbus_code = cal_camerarx_sd_enum_mbus_code,
    839	.enum_frame_size = cal_camerarx_sd_enum_frame_size,
    840	.get_fmt = cal_camerarx_sd_get_fmt,
    841	.set_fmt = cal_camerarx_sd_set_fmt,
    842};
    843
    844static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = {
    845	.video = &cal_camerarx_video_ops,
    846	.pad = &cal_camerarx_pad_ops,
    847};
    848
    849static struct media_entity_operations cal_camerarx_media_ops = {
    850	.link_validate = v4l2_subdev_link_validate,
    851};
    852
    853/* ------------------------------------------------------------------
    854 *	Create and Destroy
    855 * ------------------------------------------------------------------
    856 */
    857
    858struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
    859					 unsigned int instance)
    860{
    861	struct platform_device *pdev = to_platform_device(cal->dev);
    862	struct cal_camerarx *phy;
    863	struct v4l2_subdev *sd;
    864	unsigned int i;
    865	int ret;
    866
    867	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
    868	if (!phy)
    869		return ERR_PTR(-ENOMEM);
    870
    871	phy->cal = cal;
    872	phy->instance = instance;
    873
    874	mutex_init(&phy->mutex);
    875
    876	phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
    877						(instance == 0) ?
    878						"cal_rx_core0" :
    879						"cal_rx_core1");
    880	phy->base = devm_ioremap_resource(cal->dev, phy->res);
    881	if (IS_ERR(phy->base)) {
    882		cal_err(cal, "failed to ioremap\n");
    883		ret = PTR_ERR(phy->base);
    884		goto error;
    885	}
    886
    887	cal_dbg(1, cal, "ioresource %s at %pa - %pa\n",
    888		phy->res->name, &phy->res->start, &phy->res->end);
    889
    890	ret = cal_camerarx_regmap_init(cal, phy);
    891	if (ret)
    892		goto error;
    893
    894	ret = cal_camerarx_parse_dt(phy);
    895	if (ret)
    896		goto error;
    897
    898	/* Initialize the V4L2 subdev and media entity. */
    899	sd = &phy->subdev;
    900	v4l2_subdev_init(sd, &cal_camerarx_subdev_ops);
    901	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
    902	sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
    903	snprintf(sd->name, sizeof(sd->name), "CAMERARX%u", instance);
    904	sd->dev = cal->dev;
    905
    906	phy->pads[CAL_CAMERARX_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
    907	for (i = CAL_CAMERARX_PAD_FIRST_SOURCE; i < CAL_CAMERARX_NUM_PADS; ++i)
    908		phy->pads[i].flags = MEDIA_PAD_FL_SOURCE;
    909	sd->entity.ops = &cal_camerarx_media_ops;
    910	ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads),
    911				     phy->pads);
    912	if (ret)
    913		goto error;
    914
    915	ret = cal_camerarx_sd_init_cfg(sd, NULL);
    916	if (ret)
    917		goto error;
    918
    919	ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd);
    920	if (ret)
    921		goto error;
    922
    923	return phy;
    924
    925error:
    926	media_entity_cleanup(&phy->subdev.entity);
    927	kfree(phy);
    928	return ERR_PTR(ret);
    929}
    930
    931void cal_camerarx_destroy(struct cal_camerarx *phy)
    932{
    933	if (!phy)
    934		return;
    935
    936	v4l2_device_unregister_subdev(&phy->subdev);
    937	media_entity_cleanup(&phy->subdev.entity);
    938	of_node_put(phy->source_ep_node);
    939	of_node_put(phy->source_node);
    940	mutex_destroy(&phy->mutex);
    941	kfree(phy);
    942}