hc
2024-01-05 071106ecf68c401173c58808b1cf5f68cc50d390
kernel/drivers/media/platform/cadence/cdns-csi2tx.c
....@@ -2,7 +2,7 @@
22 /*
33 * Driver for Cadence MIPI-CSI2 TX Controller
44 *
5
- * Copyright (C) 2017-2018 Cadence Design Systems Inc.
5
+ * Copyright (C) 2017-2019 Cadence Design Systems Inc.
66 */
77
88 #include <linux/clk.h>
....@@ -52,6 +52,17 @@
5252 #define CSI2TX_STREAM_IF_CFG_REG(n) (0x100 + (n) * 4)
5353 #define CSI2TX_STREAM_IF_CFG_FILL_LEVEL(n) ((n) & 0x1f)
5454
55
+/* CSI2TX V2 Registers */
56
+#define CSI2TX_V2_DPHY_CFG_REG 0x28
57
+#define CSI2TX_V2_DPHY_CFG_RESET BIT(16)
58
+#define CSI2TX_V2_DPHY_CFG_CLOCK_MODE BIT(10)
59
+#define CSI2TX_V2_DPHY_CFG_MODE_MASK GENMASK(9, 8)
60
+#define CSI2TX_V2_DPHY_CFG_MODE_LPDT (2 << 8)
61
+#define CSI2TX_V2_DPHY_CFG_MODE_HS (1 << 8)
62
+#define CSI2TX_V2_DPHY_CFG_MODE_ULPS (0 << 8)
63
+#define CSI2TX_V2_DPHY_CFG_CLK_ENABLE BIT(4)
64
+#define CSI2TX_V2_DPHY_CFG_LANE_ENABLE(n) BIT(n)
65
+
5566 #define CSI2TX_LANES_MAX 4
5667 #define CSI2TX_STREAMS_MAX 4
5768
....@@ -70,6 +81,13 @@
7081 u32 bpp;
7182 };
7283
84
+struct csi2tx_priv;
85
+
86
+/* CSI2TX Variant Operations */
87
+struct csi2tx_vops {
88
+ void (*dphy_setup)(struct csi2tx_priv *csi2tx);
89
+};
90
+
7391 struct csi2tx_priv {
7492 struct device *dev;
7593 unsigned int count;
....@@ -81,6 +99,8 @@
8199 struct mutex lock;
82100
83101 void __iomem *base;
102
+
103
+ struct csi2tx_vops *vops;
84104
85105 struct clk *esc_clk;
86106 struct clk *p_clk;
....@@ -209,6 +229,68 @@
209229 .set_fmt = csi2tx_set_pad_format,
210230 };
211231
232
+/* Set Wake Up value in the D-PHY */
233
+static void csi2tx_dphy_set_wakeup(struct csi2tx_priv *csi2tx)
234
+{
235
+ writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
236
+ csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
237
+}
238
+
239
+/*
240
+ * Finishes the D-PHY initialization
241
+ * reg dphy cfg value to be used
242
+ */
243
+static void csi2tx_dphy_init_finish(struct csi2tx_priv *csi2tx, u32 reg)
244
+{
245
+ unsigned int i;
246
+
247
+ udelay(10);
248
+
249
+ /* Enable our (clock and data) lanes */
250
+ reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
251
+ for (i = 0; i < csi2tx->num_lanes; i++)
252
+ reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i] - 1);
253
+ writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
254
+
255
+ udelay(10);
256
+
257
+ /* Switch to HS mode */
258
+ reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
259
+ writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
260
+ csi2tx->base + CSI2TX_DPHY_CFG_REG);
261
+}
262
+
263
+/* Configures D-PHY in CSIv1.3 */
264
+static void csi2tx_dphy_setup(struct csi2tx_priv *csi2tx)
265
+{
266
+ u32 reg;
267
+ unsigned int i;
268
+
269
+ csi2tx_dphy_set_wakeup(csi2tx);
270
+
271
+ /* Put our lanes (clock and data) out of reset */
272
+ reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT;
273
+ for (i = 0; i < csi2tx->num_lanes; i++)
274
+ reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i] - 1);
275
+ writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
276
+
277
+ csi2tx_dphy_init_finish(csi2tx, reg);
278
+}
279
+
280
+/* Configures D-PHY in CSIv2 */
281
+static void csi2tx_v2_dphy_setup(struct csi2tx_priv *csi2tx)
282
+{
283
+ u32 reg;
284
+
285
+ csi2tx_dphy_set_wakeup(csi2tx);
286
+
287
+ /* Put our lanes (clock and data) out of reset */
288
+ reg = CSI2TX_V2_DPHY_CFG_RESET | CSI2TX_V2_DPHY_CFG_MODE_LPDT;
289
+ writel(reg, csi2tx->base + CSI2TX_V2_DPHY_CFG_REG);
290
+
291
+ csi2tx_dphy_init_finish(csi2tx, reg);
292
+}
293
+
212294 static void csi2tx_reset(struct csi2tx_priv *csi2tx)
213295 {
214296 writel(CSI2TX_CONFIG_SRST_REQ, csi2tx->base + CSI2TX_CONFIG_REG);
....@@ -221,7 +303,6 @@
221303 struct media_entity *entity = &csi2tx->subdev.entity;
222304 struct media_link *link;
223305 unsigned int i;
224
- u32 reg;
225306
226307 csi2tx_reset(csi2tx);
227308
....@@ -229,32 +310,10 @@
229310
230311 udelay(10);
231312
232
- /* Configure our PPI interface with the D-PHY */
233
- writel(CSI2TX_DPHY_CLK_WAKEUP_ULPS_CYCLES(32),
234
- csi2tx->base + CSI2TX_DPHY_CLK_WAKEUP_REG);
235
-
236
- /* Put our lanes (clock and data) out of reset */
237
- reg = CSI2TX_DPHY_CFG_CLK_RESET | CSI2TX_DPHY_CFG_MODE_LPDT;
238
- for (i = 0; i < csi2tx->num_lanes; i++)
239
- reg |= CSI2TX_DPHY_CFG_LANE_RESET(csi2tx->lanes[i]);
240
- writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
241
-
242
- udelay(10);
243
-
244
- /* Enable our (clock and data) lanes */
245
- reg |= CSI2TX_DPHY_CFG_CLK_ENABLE;
246
- for (i = 0; i < csi2tx->num_lanes; i++)
247
- reg |= CSI2TX_DPHY_CFG_LANE_ENABLE(csi2tx->lanes[i]);
248
- writel(reg, csi2tx->base + CSI2TX_DPHY_CFG_REG);
249
-
250
- udelay(10);
251
-
252
- /* Switch to HS mode */
253
- reg &= ~CSI2TX_DPHY_CFG_MODE_MASK;
254
- writel(reg | CSI2TX_DPHY_CFG_MODE_HS,
255
- csi2tx->base + CSI2TX_DPHY_CFG_REG);
256
-
257
- udelay(10);
313
+ if (csi2tx->vops && csi2tx->vops->dphy_setup) {
314
+ csi2tx->vops->dphy_setup(csi2tx);
315
+ udelay(10);
316
+ }
258317
259318 /*
260319 * Create a static mapping between the CSI virtual channels
....@@ -432,9 +491,9 @@
432491
433492 static int csi2tx_check_lanes(struct csi2tx_priv *csi2tx)
434493 {
435
- struct v4l2_fwnode_endpoint v4l2_ep;
494
+ struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
436495 struct device_node *ep;
437
- int ret;
496
+ int ret, i;
438497
439498 ep = of_graph_get_endpoint_by_regs(csi2tx->dev->of_node, 0, 0);
440499 if (!ep)
....@@ -446,7 +505,7 @@
446505 goto out;
447506 }
448507
449
- if (v4l2_ep.bus_type != V4L2_MBUS_CSI2) {
508
+ if (v4l2_ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
450509 dev_err(csi2tx->dev, "Unsupported media bus type: 0x%x\n",
451510 v4l2_ep.bus_type);
452511 ret = -EINVAL;
....@@ -461,6 +520,15 @@
461520 goto out;
462521 }
463522
523
+ for (i = 0; i < csi2tx->num_lanes; i++) {
524
+ if (v4l2_ep.bus.mipi_csi2.data_lanes[i] < 1) {
525
+ dev_err(csi2tx->dev, "Invalid lane[%d] number: %u\n",
526
+ i, v4l2_ep.bus.mipi_csi2.data_lanes[i]);
527
+ ret = -EINVAL;
528
+ goto out;
529
+ }
530
+ }
531
+
464532 memcpy(csi2tx->lanes, v4l2_ep.bus.mipi_csi2.data_lanes,
465533 sizeof(csi2tx->lanes));
466534
....@@ -469,9 +537,35 @@
469537 return ret;
470538 }
471539
540
+static const struct csi2tx_vops csi2tx_vops = {
541
+ .dphy_setup = csi2tx_dphy_setup,
542
+};
543
+
544
+static const struct csi2tx_vops csi2tx_v2_vops = {
545
+ .dphy_setup = csi2tx_v2_dphy_setup,
546
+};
547
+
548
+static const struct of_device_id csi2tx_of_table[] = {
549
+ {
550
+ .compatible = "cdns,csi2tx",
551
+ .data = &csi2tx_vops
552
+ },
553
+ {
554
+ .compatible = "cdns,csi2tx-1.3",
555
+ .data = &csi2tx_vops
556
+ },
557
+ {
558
+ .compatible = "cdns,csi2tx-2.1",
559
+ .data = &csi2tx_v2_vops
560
+ },
561
+ { }
562
+};
563
+MODULE_DEVICE_TABLE(of, csi2tx_of_table);
564
+
472565 static int csi2tx_probe(struct platform_device *pdev)
473566 {
474567 struct csi2tx_priv *csi2tx;
568
+ const struct of_device_id *of_id;
475569 unsigned int i;
476570 int ret;
477571
....@@ -485,6 +579,9 @@
485579 ret = csi2tx_get_resources(csi2tx, pdev);
486580 if (ret)
487581 goto err_free_priv;
582
+
583
+ of_id = of_match_node(csi2tx_of_table, pdev->dev.of_node);
584
+ csi2tx->vops = (struct csi2tx_vops *)of_id->data;
488585
489586 v4l2_subdev_init(&csi2tx->subdev, &csi2tx_subdev_ops);
490587 csi2tx->subdev.owner = THIS_MODULE;
....@@ -542,12 +639,6 @@
542639
543640 return 0;
544641 }
545
-
546
-static const struct of_device_id csi2tx_of_table[] = {
547
- { .compatible = "cdns,csi2tx" },
548
- { },
549
-};
550
-MODULE_DEVICE_TABLE(of, csi2tx_of_table);
551642
552643 static struct platform_driver csi2tx_driver = {
553644 .probe = csi2tx_probe,