[PATCH 00/18] BCM2835 DMA mapping cleanups and fixes

2024-05-24 Thread Dave Stevenson
Hi All

This series initially cleans up the BCM2835 DMA driver in preparation for
supporting the 40bit version. It then fixes up the incorrect mapping behaviour
we've had to date.

The cleanups are based on Stefan Wahren's RFC [1], with a couple of minor bugs
fixed, but stopping before actually adding the 40bit support. If we can sort
the mapping issue, it avoids having to have workarounds in the 40bit support.

The mapping issues were discussed in [2].
Up until this point all DMA users have been passing in dma addresses rather than
CPU physical addresses, and the DMA driver has been using those directly rather
than using dma_map_resource() to map them.
The DT has also been missing some of the required mappings in "dma-ranges", but
they have been present in "ranges". I've therefore duplicated the minimum amount
of of_dma_get_range and translate_phys_to_dma to be able to use "ranges" as 
discussed in that thread. I'm assuming that sort of code is not desirable in the
core code as it shouldn't be necessary, so keeping it contained within a driver
is the better solution.

When Andrea posted our downstream patches in [3], Robin Murphy stated that
dma_map_resource is the correct API, but as it currently doesn't check the
dma_range_map we need Sergey Semin's patch [4].
There seemed to be no follow up over the implications of it. I've therefore
included it in the series at least for discussion. If it's not acceptable then
I'm not sure of the route forward in fixing this mapping issue.

I'm expecting there to be some discussion, but also acknowledge that merging 
this
will need to be phased with the patches 1-13 needing to be merged before any of
14-17, and then 18 merged last to remove the workaround. I suspect that's the
least of my worries though.


I will apologise in advance if I don't respond immediately to comments - I'm
out of the office for the next week, but do appreciate any feedback.

Thanks
  Dave

[1] 
https://lore.kernel.org/linux-arm-kernel/13ec386b-2305-27da-9765-8fa3ad711...@i2se.com/T/
[2] 
https://lore.kernel.org/linux-arm-kernel/CAPY8ntBua=wpvuj+sm0wgcul0ft56ueho8yzutmb8z54x_a...@mail.gmail.com/T/
[3] https://lore.kernel.org/lkml/cover.1706948717.git.andrea.po...@suse.com/T/
[4] 
https://lore.kernel.org/linux-iommu/20220610080802.11147-1-sergey.se...@baikalelectronics.ru/

Dave Stevenson (7):
  ARM: dts: bcm283x: Update to use dma-channel-mask
  dmaengine: bcm2835: Add function to handle DMA mapping
  dmaengine: bcm2835: Add backwards compatible handling until clients
updated
  dmaengine: bcm2835: Use dma_map_resource to map addresses
  dmaengine: bcm2835: Read ranges if dma-ranges aren't mapped
  arm: dt: Add dma-ranges to the bcm283x platforms
  dmaengine: bcm2835: Revert the workaround for DMA addresses

Phil Elwell (4):
  mmc: bcm2835: Use phys addresses for slave DMA config
  spi: bcm2835: Use phys addresses for slave DMA config
  drm/vc4: Use phys addresses for slave DMA config
  ASoC: bcm2835-i2s: Use phys addresses for DAI DMA

Serge Semin (1):
  dma-direct: take dma-ranges/offsets into account in resource mapping

Stefan Wahren (6):
  dmaengine: bcm2835: Support common dma-channel-mask
  dmaengine: bcm2835: move CB info generation into separate function
  dmaengine: bcm2835: move CB final extra info generation into function
  dmaengine: bcm2835: make address increment platform independent
  dmaengine: bcm2385: drop info parameters
  dmaengine: bcm2835: pass dma_chan to generic functions

 arch/arm/boot/dts/broadcom/bcm2711.dtsi   |  14 +-
 .../arm/boot/dts/broadcom/bcm2835-common.dtsi |   2 +-
 arch/arm/boot/dts/broadcom/bcm2835.dtsi   |   3 +-
 arch/arm/boot/dts/broadcom/bcm2836.dtsi   |   3 +-
 arch/arm/boot/dts/broadcom/bcm2837.dtsi   |   3 +-
 drivers/dma/bcm2835-dma.c | 432 ++
 drivers/gpu/drm/vc4/vc4_hdmi.c|  15 +-
 drivers/mmc/host/bcm2835.c|  17 +-
 drivers/spi/spi-bcm2835.c |  23 +-
 kernel/dma/direct.c   |   2 +-
 sound/soc/bcm/bcm2835-i2s.c   |  18 +-
 11 files changed, 383 insertions(+), 149 deletions(-)

-- 
2.34.1



[PATCH 09/18] dmaengine: bcm2835: Add function to handle DMA mapping

2024-05-24 Thread Dave Stevenson
The code handling DMA mapping is currently incorrect and
needs a sequence of fixups.
Move the mapping out into a separate function and structure
to allow for those fixes to be applied more cleanly.

Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 46 ---
 1 file changed, 38 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index aefaa1f01d7f..ef1d95bae84e 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -65,6 +65,10 @@ struct bcm2835_cb_entry {
dma_addr_t paddr;
 };
 
+struct bcm2835_dma_chan_map {
+   dma_addr_t addr;
+};
+
 struct bcm2835_chan {
struct virt_dma_chan vc;
 
@@ -74,6 +78,7 @@ struct bcm2835_chan {
int ch;
struct bcm2835_desc *desc;
struct dma_pool *cb_pool;
+   struct bcm2835_dma_chan_map map;
 
void __iomem *chan_base;
int irq_number;
@@ -268,6 +273,19 @@ static inline bool need_dst_incr(enum 
dma_transfer_direction direction)
}
 
return false;
+};
+
+static int bcm2835_dma_map_slave_addr(struct dma_chan *chan,
+ phys_addr_t dev_addr,
+ size_t dev_size,
+ enum dma_data_direction dev_dir)
+{
+   struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+   struct bcm2835_dma_chan_map *map = >map;
+
+   map->addr = dev_addr;
+
+   return 0;
 }
 
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
@@ -734,13 +752,19 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_slave_sg(
}
 
if (direction == DMA_DEV_TO_MEM) {
-   if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+   if (bcm2835_dma_map_slave_addr(chan, c->cfg.src_addr,
+  c->cfg.src_addr_width,
+  DMA_TO_DEVICE))
return NULL;
-   src = c->cfg.src_addr;
+
+   src = c->map.addr;
} else {
-   if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+   if (bcm2835_dma_map_slave_addr(chan, c->cfg.dst_addr,
+  c->cfg.dst_addr_width,
+  DMA_FROM_DEVICE))
return NULL;
-   dst = c->cfg.dst_addr;
+
+   dst = c->map.addr;
}
 
/* count frames in sg list */
@@ -795,14 +819,20 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_cyclic(
  __func__, buf_len, period_len);
 
if (direction == DMA_DEV_TO_MEM) {
-   if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+   if (bcm2835_dma_map_slave_addr(chan, c->cfg.src_addr,
+  c->cfg.src_addr_width,
+  DMA_TO_DEVICE))
return NULL;
-   src = c->cfg.src_addr;
+
+   src = c->map.addr;
dst = buf_addr;
} else {
-   if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
+   if (bcm2835_dma_map_slave_addr(chan, c->cfg.dst_addr,
+  c->cfg.dst_addr_width,
+  DMA_FROM_DEVICE))
return NULL;
-   dst = c->cfg.dst_addr;
+
+   dst = c->map.addr;
src = buf_addr;
}
 
-- 
2.34.1



[PATCH 17/18] ASoC: bcm2835-i2s: Use phys addresses for DAI DMA

2024-05-24 Thread Dave Stevenson
From: Phil Elwell 

Contrary to what struct snd_dmaengine_dai_dma_data suggests, the
configuration of addresses of DMA slave interfaces should be done in
CPU physical addresses.

Signed-off-by: Phil Elwell 
Signed-off-by: Dave Stevenson 
---
 sound/soc/bcm/bcm2835-i2s.c | 18 --
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c
index 9bda6499e66e..2d0fe53245f0 100644
--- a/sound/soc/bcm/bcm2835-i2s.c
+++ b/sound/soc/bcm/bcm2835-i2s.c
@@ -30,7 +30,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 
 #include 
@@ -830,8 +829,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
struct bcm2835_i2s_dev *dev;
int ret;
void __iomem *base;
-   const __be32 *addr;
-   dma_addr_t dma_base;
+   struct resource *res;
 
dev = devm_kzalloc(>dev, sizeof(*dev),
   GFP_KERNEL);
@@ -846,7 +844,7 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
 "could not get clk\n");
 
/* Request ioarea */
-   base = devm_platform_ioremap_resource(pdev, 0);
+   base = devm_platform_get_and_ioremap_resource(pdev, 0, );
if (IS_ERR(base))
return PTR_ERR(base);
 
@@ -855,19 +853,11 @@ static int bcm2835_i2s_probe(struct platform_device *pdev)
if (IS_ERR(dev->i2s_regmap))
return PTR_ERR(dev->i2s_regmap);
 
-   /* Set the DMA address - we have to parse DT ourselves */
-   addr = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
-   if (!addr) {
-   dev_err(>dev, "could not get DMA-register address\n");
-   return -EINVAL;
-   }
-   dma_base = be32_to_cpup(addr);
-
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr =
-   dma_base + BCM2835_I2S_FIFO_A_REG;
+   res->start + BCM2835_I2S_FIFO_A_REG;
 
dev->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr =
-   dma_base + BCM2835_I2S_FIFO_A_REG;
+   res->start + BCM2835_I2S_FIFO_A_REG;
 
/* Set the bus width */
dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr_width =
-- 
2.34.1



[PATCH 13/18] arm: dt: Add dma-ranges to the bcm283x platforms

2024-05-24 Thread Dave Stevenson
In order to use the dma_map_resource for mappings, add the
dma-ranges to the relevant DT files.

Signed-off-by: Dave Stevenson 
---
 arch/arm/boot/dts/broadcom/bcm2711.dtsi | 12 ++--
 arch/arm/boot/dts/broadcom/bcm2835.dtsi |  3 ++-
 arch/arm/boot/dts/broadcom/bcm2836.dtsi |  3 ++-
 arch/arm/boot/dts/broadcom/bcm2837.dtsi |  3 ++-
 4 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
index d64bf098b697..d6f32d32b456 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -42,7 +42,8 @@ soc {
 <0x7c00  0x0 0xfc00  0x0200>,
 <0x4000  0x0 0xff80  0x0080>;
/* Emulate a contiguous 30-bit address range for DMA */
-   dma-ranges = <0xc000  0x0 0x  0x4000>;
+   dma-ranges = <0xc000  0x0 0x  0x4000>,
+<0x7c00  0x0 0xfc00  0x0380>;
 
/*
 * This node is the provider for the enable-method for
@@ -550,7 +551,14 @@ scb {
#size-cells = <1>;
 
ranges = <0x0 0x7c00  0x0 0xfc00  0x0380>,
-<0x6 0x  0x6 0x  0x4000>;
+<0x0 0x4000  0x0 0xff80  0x0080>,
+<0x6 0x  0x6 0x  0x4000>,
+<0x0 0x  0x0 0x  0xfc00>;
+   dma-ranges = <0x4 0x7c00  0x0 0xfc00  0x0380>,
+<0x0 0x  0x0 0x  0x8000>,
+<0x0 0x8000  0x0 0x8000  0x8000>,
+<0x1 0x  0x1 0x  0x8000>,
+<0x1 0x8000  0x1 0x8000  0x8000>;
 
pcie0: pcie@7d50 {
compatible = "brcm,bcm2711-pcie";
diff --git a/arch/arm/boot/dts/broadcom/bcm2835.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2835.dtsi
index 15cb331febbb..480e12fd8a17 100644
--- a/arch/arm/boot/dts/broadcom/bcm2835.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2835.dtsi
@@ -35,7 +35,8 @@ cpu@0 {
 
soc {
ranges = <0x7e00 0x2000 0x0200>;
-   dma-ranges = <0x4000 0x 0x2000>;
+   dma-ranges = <0x8000 0x 0x2000>,
+<0x7e00 0x2000 0x0200>;
};
 
arm-pmu {
diff --git a/arch/arm/boot/dts/broadcom/bcm2836.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2836.dtsi
index 783fe624ba68..4ab7769c056a 100644
--- a/arch/arm/boot/dts/broadcom/bcm2836.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2836.dtsi
@@ -8,7 +8,8 @@ / {
soc {
ranges = <0x7e00 0x3f00 0x100>,
 <0x4000 0x4000 0x1000>;
-   dma-ranges = <0xc000 0x 0x3f00>;
+   dma-ranges = <0xc000 0x 0x3f00>,
+<0x7e00 0x3f00 0x0100>;
 
local_intc: interrupt-controller@4000 {
compatible = "brcm,bcm2836-l1-intc";
diff --git a/arch/arm/boot/dts/broadcom/bcm2837.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2837.dtsi
index 84c08b46519d..d034d6a8caad 100644
--- a/arch/arm/boot/dts/broadcom/bcm2837.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2837.dtsi
@@ -7,7 +7,8 @@ / {
soc {
ranges = <0x7e00 0x3f00 0x100>,
 <0x4000 0x4000 0x1000>;
-   dma-ranges = <0xc000 0x 0x3f00>;
+   dma-ranges = <0xc000 0x 0x3f00>,
+<0x7e00 0x3f00 0x0100>;
 
local_intc: local_intc@4000 {
compatible = "brcm,bcm2836-l1-intc";
-- 
2.34.1



[PATCH 14/18] mmc: bcm2835: Use phys addresses for slave DMA config

2024-05-24 Thread Dave Stevenson
From: Phil Elwell 

Contrary to what struct snd_dmaengine_dai_dma_data suggests, the
configuration of addresses of DMA slave interfaces should be done in
CPU physical addresses.

Signed-off-by: Phil Elwell 
Signed-off-by: Dave Stevenson 
---
 drivers/mmc/host/bcm2835.c | 17 +++--
 1 file changed, 3 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c
index 35d8fdea668b..746a60fac0f0 100644
--- a/drivers/mmc/host/bcm2835.c
+++ b/drivers/mmc/host/bcm2835.c
@@ -38,7 +38,6 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 #include 
@@ -1347,8 +1346,8 @@ static int bcm2835_probe(struct platform_device *pdev)
struct device *dev = >dev;
struct clk *clk;
struct bcm2835_host *host;
+   struct resource *iomem;
struct mmc_host *mmc;
-   const __be32 *regaddr_p;
int ret;
 
dev_dbg(dev, "%s\n", __func__);
@@ -1361,23 +1360,13 @@ static int bcm2835_probe(struct platform_device *pdev)
host->pdev = pdev;
spin_lock_init(>lock);
 
-   host->ioaddr = devm_platform_ioremap_resource(pdev, 0);
+   host->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, );
if (IS_ERR(host->ioaddr)) {
ret = PTR_ERR(host->ioaddr);
goto err;
}
 
-   /* Parse OF address directly to get the physical address for
-* DMA to our registers.
-*/
-   regaddr_p = of_get_address(pdev->dev.of_node, 0, NULL, NULL);
-   if (!regaddr_p) {
-   dev_err(dev, "Can't get phys address\n");
-   ret = -EINVAL;
-   goto err;
-   }
-
-   host->phys_addr = be32_to_cpup(regaddr_p);
+   host->phys_addr = iomem->start;
 
host->dma_chan = NULL;
host->dma_desc = NULL;
-- 
2.34.1



[PATCH 18/18] dmaengine: bcm2835: Revert the workaround for DMA addresses

2024-05-24 Thread Dave Stevenson
Now that all DMA clients are passing in CPU addresses, drop
the workaround that would accept those and not try mapping
them.

Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 11 ---
 1 file changed, 11 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 06407691ef28..181f2c291109 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -405,17 +405,6 @@ static int bcm2835_dma_map_slave_addr(struct dma_chan 
*chan,
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_dma_chan_map *map = >map;
 
-   if ((dev_addr & 0xfe00ULL) == 0x7e00ULL) {
-   /*
-* Address is already in the 0x7e... peripherals range.
-* Assume this is an old client that hasn't been updated to
-* correctly pass a cpu phys_addr to the DMA subsystem.
-*/
-   map->addr = dev_addr;
-
-   return 0;
-   }
-
if (dev_size != DMA_SLAVE_BUSWIDTH_4_BYTES)
return -EIO;
 
-- 
2.34.1



[PATCH 10/18] dmaengine: bcm2835: Add backwards compatible handling until clients updated

2024-05-24 Thread Dave Stevenson
bcm2835-dma has been (incorrectly) expecting dma addresses to be
passed in, not CPU physical addresses.

In order to fix this up, add temporary handling of clients still
passing in dma addresses until they are fixed up.
This will be reverted once all clients have been fixed.

Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 18 --
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index ef1d95bae84e..9531c0b82071 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -283,9 +283,23 @@ static int bcm2835_dma_map_slave_addr(struct dma_chan 
*chan,
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_dma_chan_map *map = >map;
 
-   map->addr = dev_addr;
+   if ((dev_addr & 0xfe00ULL) == 0x7e00ULL) {
+   /*
+* Address is already in the 0x7e... peripherals range.
+* Assume this is an old client that hasn't been updated to
+* correctly pass a cpu phys_addr to the DMA subsystem.
+*/
+   map->addr = dev_addr;
 
-   return 0;
+   return 0;
+   }
+
+   /*
+* This path will be updated to handle new clients, but currently should
+* never be used.
+*/
+
+   return -EINVAL;
 }
 
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
-- 
2.34.1



[PATCH 12/18] dmaengine: bcm2835: Read ranges if dma-ranges aren't mapped

2024-05-24 Thread Dave Stevenson
We have a historical error in the DT files that don't define
the dma-ranges fully, and DMA users have been passing in
DMA addresses instead of CPU physical addresses.

As DT is ABI, we have to be able to work with old DT but new
kernel, which means handling this missing dma-range mapping
somehow.
The "ranges" property has always been defined correctly, so
abuse that in the event that dma-ranges are missing.

There appears to be no easy route to access "ranges", so
duplicate the functions for handling "dma-ranges" here to
keep the hack contained.

Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 139 --
 1 file changed, 134 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index e48008b06716..06407691ef28 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -37,6 +38,12 @@
 #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14
 #define BCM2835_DMA_CHAN_NAME_SIZE 8
 
+struct bcm2835_bus_dma_region {
+   phys_addr_t cpu_start;
+   dma_addr_t  dma_start;
+   u64 size;
+};
+
 /**
  * struct bcm2835_dmadev - BCM2835 DMA controller
  * @ddev: DMA device
@@ -48,6 +55,8 @@ struct bcm2835_dmadev {
struct dma_device ddev;
void __iomem *base;
dma_addr_t zero_page;
+   bool ranges_initialised;
+   struct bcm2835_bus_dma_region *ranges_map;
 };
 
 struct bcm2835_dma_cb {
@@ -71,6 +80,7 @@ struct bcm2835_dma_chan_map {
 
phys_addr_t slave_addr;
unsigned int xfer_size;
+   bool ranges;
 };
 
 struct bcm2835_chan {
@@ -279,6 +289,114 @@ static inline bool need_dst_incr(enum 
dma_transfer_direction direction)
return false;
 };
 
+static int bcm2835_dma_init_ranges(struct dma_chan *chan)
+{
+   struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device);
+   struct device *dev = chan->device->dev;
+   struct device_node *node = of_node_get(dev->of_node);
+   const __be32 *ranges = NULL;
+   bool found_ranges = false;
+   struct of_range_parser parser;
+   struct of_range range;
+   struct bcm2835_bus_dma_region *r;
+   int len, num_ranges = 0;
+   int ret = 0;
+
+   while (node) {
+   ranges = of_get_property(node, "ranges", );
+
+   /* Ignore empty ranges, they imply no translation required */
+   if (ranges && len > 0)
+   break;
+
+   /* Once we find 'dma-ranges', then a missing one is an error */
+   if (found_ranges && !ranges) {
+   ret = -ENODEV;
+   goto out;
+   }
+   found_ranges = true;
+
+   node = of_get_next_parent(node);
+   }
+
+   if (!node || !ranges) {
+   pr_debug("no ranges found for node(%pOF)\n", dev->of_node);
+   ret = -ENODEV;
+   goto out;
+   }
+
+   of_pci_range_parser_init(, node);
+   for_each_of_range(, ) {
+   if (range.cpu_addr == OF_BAD_ADDR) {
+   pr_err("translation of DMA address(%llx) to CPU address 
failed node(%pOF)\n",
+  range.bus_addr, node);
+   continue;
+   }
+   num_ranges++;
+   }
+
+   if (!num_ranges) {
+   ret = -EINVAL;
+   goto out;
+   }
+
+   r = kcalloc(num_ranges + 1, sizeof(*r), GFP_KERNEL);
+   if (!r) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   /*
+* Record all info in the generic DMA ranges array for struct device,
+* returning an error if we don't find any parsable ranges.
+*/
+   od->ranges_map = r;
+   of_pci_range_parser_init(, node);
+   for_each_of_range(, ) {
+   pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n",
+range.bus_addr, range.cpu_addr, range.size);
+   if (range.cpu_addr == OF_BAD_ADDR)
+   continue;
+   r->cpu_start = range.cpu_addr;
+   r->dma_start = range.bus_addr;
+   r->size = range.size;
+   r++;
+   }
+out:
+   of_node_put(node);
+   return ret;
+}
+
+static dma_addr_t bcm2835_translate_phys_to_dma(struct bcm2835_dmadev *od,
+   phys_addr_t paddr)
+{
+   const struct bcm2835_bus_dma_region *m;
+
+   for (m = od->ranges_map; m && m->size; m++) {
+   u64 offset = paddr - m->cpu_start;
+
+   if (paddr >= m->cpu_start && offset < m->size)
+   return m->dma_start + offset;
+   }
+
+   /* make sure 

[PATCH 11/18] dmaengine: bcm2835: Use dma_map_resource to map addresses

2024-05-24 Thread Dave Stevenson
There is a need to account for dma-ranges and iommus in the
dma mapping process, and the public API for handling that is
dma_map_resource.

Add support for mapping addresses to the DMA driver.

Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 46 ++-
 1 file changed, 41 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 9531c0b82071..e48008b06716 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -67,6 +67,10 @@ struct bcm2835_cb_entry {
 
 struct bcm2835_dma_chan_map {
dma_addr_t addr;
+   enum dma_data_direction dir;
+
+   phys_addr_t slave_addr;
+   unsigned int xfer_size;
 };
 
 struct bcm2835_chan {
@@ -294,12 +298,44 @@ static int bcm2835_dma_map_slave_addr(struct dma_chan 
*chan,
return 0;
}
 
-   /*
-* This path will be updated to handle new clients, but currently should
-* never be used.
-*/
+   if (dev_size != DMA_SLAVE_BUSWIDTH_4_BYTES)
+   return -EIO;
+
+   /* Reuse current map if possible. */
+   if (dev_addr == map->slave_addr &&
+   dev_size == map->xfer_size &&
+   dev_dir == map->dir)
+   return 0;
+
+   /* Remove old mapping if present. */
+   if (map->xfer_size) {
+   dev_dbg(chan->device->dev, "chan: unmap %zx@%pap to %pad dir: 
%s\n",
+   dev_size, _addr, >addr,
+   dev_dir == DMA_TO_DEVICE ? "DMA_TO_DEVICE" : 
"DMA_FROM_DEVICE");
+   dma_unmap_resource(chan->device->dev, map->addr,
+  map->xfer_size, map->dir, 0);
+   }
+   map->xfer_size = 0;
 
-   return -EINVAL;
+   /* Create new slave address map. */
+   map->addr = dma_map_resource(chan->device->dev, dev_addr, dev_size,
+dev_dir, 0);
+
+   if (dma_mapping_error(chan->device->dev, map->addr)) {
+   dev_err(chan->device->dev, "chan: failed to map %zx@%pap",
+   dev_size, _addr);
+   return -EIO;
+   }
+
+   dev_dbg(chan->device->dev, "chan: map %zx@%pap to %pad dir: %s\n",
+   dev_size, _addr, >addr,
+   dev_dir == DMA_TO_DEVICE ? "DMA_TO_DEVICE" : "DMA_FROM_DEVICE");
+
+   map->slave_addr = dev_addr;
+   map->xfer_size = dev_size;
+   map->dir = dev_dir;
+
+   return 0;
 }
 
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
-- 
2.34.1



[PATCH 02/18] dmaengine: bcm2835: Support common dma-channel-mask

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

Nowadays there is a generic property for dma-channel-mask in the DMA
controller binding. So prefer this one instead of the old vendor specific
one. Print a warning in case the old one is used. Btw use the result of
of_property_read_u32() as return code in error case.

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 19 +--
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 9d74fe97452e..528c4593b45a 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -941,12 +941,19 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
}
 
/* Request DMA channel mask from device tree */
-   if (of_property_read_u32(pdev->dev.of_node,
-   "brcm,dma-channel-mask",
-   _available)) {
-   dev_err(>dev, "Failed to get channel mask\n");
-   rc = -EINVAL;
-   goto err_no_dma;
+   rc = of_property_read_u32(pdev->dev.of_node, "dma-channel-mask",
+ _available);
+
+   if (rc) {
+   /* Try deprecated property */
+   if (of_property_read_u32(pdev->dev.of_node,
+"brcm,dma-channel-mask",
+_available)) {
+   dev_err(>dev, "Failed to get channel mask\n");
+   goto err_no_dma;
+   }
+
+   dev_warn(>dev, "brcm,dma-channel-mask deprecated - please 
update DT\n");
}
 
/* get irqs for each channel that we support */
-- 
2.34.1



[PATCH 16/18] drm/vc4: Use phys addresses for slave DMA config

2024-05-24 Thread Dave Stevenson
From: Phil Elwell 

Slave addresses for DMA are meant to be supplied as physical addresses
(contrary to what struct snd_dmaengine_dai_dma_data does).

Signed-off-by: Phil Elwell 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/vc4/vc4_hdmi.c | 15 ---
 1 file changed, 4 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index d30f8e8e8967..c2afd72bd96e 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -2696,7 +2696,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
struct snd_soc_card *card = _hdmi->audio.card;
struct device *dev = _hdmi->pdev->dev;
struct platform_device *codec_pdev;
-   const __be32 *addr;
+   struct resource *iomem;
int index, len;
int ret;
 
@@ -2732,22 +2732,15 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi 
*vc4_hdmi)
}
 
/*
-* Get the physical address of VC4_HD_MAI_DATA. We need to retrieve
-* the bus address specified in the DT, because the physical address
-* (the one returned by platform_get_resource()) is not appropriate
-* for DMA transfers.
-* This VC/MMU should probably be exposed to avoid this kind of hacks.
+* Get the physical address of VC4_HD_MAI_DATA.
 */
index = of_property_match_string(dev->of_node, "reg-names", "hd");
/* Before BCM2711, we don't have a named register range */
if (index < 0)
index = 1;
+   iomem = platform_get_resource(vc4_hdmi->pdev, IORESOURCE_MEM, index);
 
-   addr = of_get_address(dev->of_node, index, NULL, NULL);
-   if (!addr)
-   return -EINVAL;
-
-   vc4_hdmi->audio.dma_data.addr = be32_to_cpup(addr) + mai_data->offset;
+   vc4_hdmi->audio.dma_data.addr = iomem->start + mai_data->offset;
vc4_hdmi->audio.dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
vc4_hdmi->audio.dma_data.maxburst = 2;
 
-- 
2.34.1



[PATCH 15/18] spi: bcm2835: Use phys addresses for slave DMA config

2024-05-24 Thread Dave Stevenson
From: Phil Elwell 

Contrary to what struct snd_dmaengine_dai_dma_data suggests, the
configuration of addresses of DMA slave interfaces should be done in
CPU physical addresses.

Signed-off-by: Phil Elwell 
Signed-off-by: Dave Stevenson 
---
 drivers/spi/spi-bcm2835.c | 23 ---
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index e1b9b1235787..e8242e0c4246 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -119,6 +119,7 @@ MODULE_PARM_DESC(polling_limit_us,
  */
 struct bcm2835_spi {
void __iomem *regs;
+   phys_addr_t phys_addr;
struct clk *clk;
struct gpio_desc *cs_gpio;
unsigned long clk_hz;
@@ -891,19 +892,8 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, 
struct device *dev,
struct bcm2835_spi *bs)
 {
struct dma_slave_config slave_config;
-   const __be32 *addr;
-   dma_addr_t dma_reg_base;
int ret;
 
-   /* base address in dma-space */
-   addr = of_get_address(ctlr->dev.of_node, 0, NULL, NULL);
-   if (!addr) {
-   dev_err(dev, "could not get DMA-register address - not using 
dma mode\n");
-   /* Fall back to interrupt mode */
-   return 0;
-   }
-   dma_reg_base = be32_to_cpup(addr);
-
/* get tx/rx dma */
ctlr->dma_tx = dma_request_chan(dev, "tx");
if (IS_ERR(ctlr->dma_tx)) {
@@ -925,7 +915,7 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, 
struct device *dev,
 * or, in case of an RX-only transfer, cyclically copies from the zero
 * page to the FIFO using a preallocated, reusable descriptor.
 */
-   slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
+   slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_FIFO;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
ret = dmaengine_slave_config(ctlr->dma_tx, _config);
@@ -964,9 +954,9 @@ static int bcm2835_dma_init(struct spi_controller *ctlr, 
struct device *dev,
 * RX FIFO or, in case of a TX-only transfer, cyclically writes a
 * precalculated value to the CS register to clear the RX FIFO.
 */
-   slave_config.src_addr = (u32)(dma_reg_base + BCM2835_SPI_FIFO);
+   slave_config.src_addr = bs->phys_addr + BCM2835_SPI_FIFO;
slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-   slave_config.dst_addr = (u32)(dma_reg_base + BCM2835_SPI_CS);
+   slave_config.dst_addr = bs->phys_addr + BCM2835_SPI_CS;
slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
 
ret = dmaengine_slave_config(ctlr->dma_rx, _config);
@@ -1336,6 +1326,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
 {
struct spi_controller *ctlr;
struct bcm2835_spi *bs;
+   struct resource *iomem;
int err;
 
ctlr = devm_spi_alloc_host(>dev, sizeof(*bs));
@@ -1359,10 +1350,12 @@ static int bcm2835_spi_probe(struct platform_device 
*pdev)
bs = spi_controller_get_devdata(ctlr);
bs->ctlr = ctlr;
 
-   bs->regs = devm_platform_ioremap_resource(pdev, 0);
+   bs->regs = devm_platform_get_and_ioremap_resource(pdev, 0, );
if (IS_ERR(bs->regs))
return PTR_ERR(bs->regs);
 
+   bs->phys_addr = iomem->start;
+
bs->clk = devm_clk_get_enabled(>dev, NULL);
if (IS_ERR(bs->clk))
return dev_err_probe(>dev, PTR_ERR(bs->clk),
-- 
2.34.1



[PATCH 08/18] dmaengine: bcm2835: pass dma_chan to generic functions

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

In preparation to support more platforms pass the dma_chan to the
generic functions. This provides access to the DMA device and possible
platform specific data.

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 24 ++--
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index e2f9c8692e6b..aefaa1f01d7f 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -288,12 +288,13 @@ static void bcm2835_dma_desc_free(struct virt_dma_desc 
*vd)
 }
 
 static bool
-bcm2835_dma_create_cb_set_length(struct bcm2835_chan *chan,
+bcm2835_dma_create_cb_set_length(struct dma_chan *chan,
 struct bcm2835_dma_cb *control_block,
 size_t len, size_t period_len,
 size_t *total_len)
 {
-   size_t max_len = bcm2835_dma_max_frame_length(chan);
+   struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+   size_t max_len = bcm2835_dma_max_frame_length(c);
 
/* set the length taking lite-channel limitations into account */
control_block->length = min_t(u32, len, max_len);
@@ -417,7 +418,7 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
/* set up length in control_block if requested */
if (buf_len) {
/* calculate length honoring period_length */
-   if (bcm2835_dma_create_cb_set_length(c, control_block,
+   if (bcm2835_dma_create_cb_set_length(chan, 
control_block,
 len, period_len,
 _len)) {
/* add extrainfo bits in info */
@@ -485,8 +486,9 @@ static void bcm2835_dma_fill_cb_chain_with_sg(
}
 }
 
-static void bcm2835_dma_abort(struct bcm2835_chan *c)
+static void bcm2835_dma_abort(struct dma_chan *chan)
 {
+   struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
void __iomem *chan_base = c->chan_base;
long int timeout = 1;
 
@@ -513,8 +515,9 @@ static void bcm2835_dma_abort(struct bcm2835_chan *c)
writel(BCM2835_DMA_RESET, chan_base + BCM2835_DMA_CS);
 }
 
-static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
+static void bcm2835_dma_start_desc(struct dma_chan *chan)
 {
+   struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct virt_dma_desc *vd = vchan_next_desc(>vc);
struct bcm2835_desc *d;
 
@@ -533,7 +536,8 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
 
 static irqreturn_t bcm2835_dma_callback(int irq, void *data)
 {
-   struct bcm2835_chan *c = data;
+   struct dma_chan *chan = data;
+   struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_desc *d;
unsigned long flags;
 
@@ -566,7 +570,7 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
vchan_cyclic_callback(>vd);
} else if (!readl(c->chan_base + BCM2835_DMA_ADDR)) {
vchan_cookie_complete(>desc->vd);
-   bcm2835_dma_start_desc(c);
+   bcm2835_dma_start_desc(chan);
}
}
 
@@ -594,7 +598,7 @@ static int bcm2835_dma_alloc_chan_resources(struct dma_chan 
*chan)
}
 
return request_irq(c->irq_number, bcm2835_dma_callback,
-  c->irq_flags, "DMA IRQ", c);
+  c->irq_flags, "DMA IRQ", chan);
 }
 
 static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
@@ -682,7 +686,7 @@ static void bcm2835_dma_issue_pending(struct dma_chan *chan)
 
spin_lock_irqsave(>vc.lock, flags);
if (vchan_issue_pending(>vc) && !c->desc)
-   bcm2835_dma_start_desc(c);
+   bcm2835_dma_start_desc(chan);
 
spin_unlock_irqrestore(>vc.lock, flags);
 }
@@ -846,7 +850,7 @@ static int bcm2835_dma_terminate_all(struct dma_chan *chan)
if (c->desc) {
vchan_terminate_vdesc(>desc->vd);
c->desc = NULL;
-   bcm2835_dma_abort(c);
+   bcm2835_dma_abort(chan);
}
 
vchan_get_all_descriptors(>vc, );
-- 
2.34.1



[PATCH 07/18] dmaengine: bcm2385: drop info parameters

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

The parameters info and finalextrainfo are platform specific. So drop
them by generating them within bcm2835_dma_create_cb_chain().

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 83 +++
 1 file changed, 40 insertions(+), 43 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index d6c5a2762a46..e2f9c8692e6b 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -287,13 +287,11 @@ static void bcm2835_dma_desc_free(struct virt_dma_desc 
*vd)
container_of(vd, struct bcm2835_desc, vd));
 }
 
-static void bcm2835_dma_create_cb_set_length(
-   struct bcm2835_chan *chan,
-   struct bcm2835_dma_cb *control_block,
-   size_t len,
-   size_t period_len,
-   size_t *total_len,
-   u32 finalextrainfo)
+static bool
+bcm2835_dma_create_cb_set_length(struct bcm2835_chan *chan,
+struct bcm2835_dma_cb *control_block,
+size_t len, size_t period_len,
+size_t *total_len)
 {
size_t max_len = bcm2835_dma_max_frame_length(chan);
 
@@ -302,7 +300,7 @@ static void bcm2835_dma_create_cb_set_length(
 
/* finished if we have no period_length */
if (!period_len)
-   return;
+   return false;
 
/*
 * period_len means: that we need to generate
@@ -316,7 +314,7 @@ static void bcm2835_dma_create_cb_set_length(
if (*total_len + control_block->length < period_len) {
/* update number of bytes in this period so far */
*total_len += control_block->length;
-   return;
+   return false;
}
 
/* calculate the length that remains to reach period_length */
@@ -325,8 +323,7 @@ static void bcm2835_dma_create_cb_set_length(
/* reset total_length for next period */
*total_len = 0;
 
-   /* add extrainfo bits in info */
-   control_block->info |= finalextrainfo;
+   return true;
 }
 
 static inline size_t bcm2835_dma_count_frames_for_sg(
@@ -352,7 +349,6 @@ static inline size_t bcm2835_dma_count_frames_for_sg(
  * @chan:   the @dma_chan for which we run this
  * @direction:  the direction in which we transfer
  * @cyclic: it is a cyclic transfer
- * @info:   the default info bits to apply per controlblock
  * @frames: number of controlblocks to allocate
  * @src:the src address to assign
  * @dst:the dst address to assign
@@ -360,22 +356,24 @@ static inline size_t bcm2835_dma_count_frames_for_sg(
  * @period_len: the period length when to apply @finalextrainfo
  *  in addition to the last transfer
  *  this will also break some control-blocks early
- * @finalextrainfo: additional bits in last controlblock
- *  (or when period_len is reached in case of cyclic)
  * @gfp:the GFP flag to use for allocation
+ * @flags
  */
 static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
struct dma_chan *chan, enum dma_transfer_direction direction,
-   bool cyclic, u32 info, u32 finalextrainfo, size_t frames,
-   dma_addr_t src, dma_addr_t dst, size_t buf_len,
-   size_t period_len, gfp_t gfp)
+   bool cyclic, size_t frames, dma_addr_t src, dma_addr_t dst,
+   size_t buf_len, size_t period_len, gfp_t gfp, unsigned long flags)
 {
+   struct bcm2835_dmadev *od = to_bcm2835_dma_dev(chan->device);
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
size_t len = buf_len, total_len;
size_t frame;
struct bcm2835_desc *d;
struct bcm2835_cb_entry *cb_entry;
struct bcm2835_dma_cb *control_block;
+   u32 extrainfo = bcm2835_dma_prepare_cb_extra(c, direction, cyclic,
+false, flags);
+   bool zero_page = false;
 
if (!frames)
return NULL;
@@ -389,6 +387,14 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
d->dir = direction;
d->cyclic = cyclic;
 
+   switch (direction) {
+   case DMA_MEM_TO_MEM:
+   case DMA_DEV_TO_MEM:
+   break;
+   default:
+   zero_page = src == od->zero_page;
+   }
+
/*
 * Iterate over all frames, create a control block
 * for each frame and link them together.
@@ -402,7 +408,8 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
 
/* fill in the control block */
control_block = cb_entry->cb;
-   control_block->info = info;
+   control_block->info = bcm2835_dma_prepare_cb_info(c, direction,
+ zero_page);
control_block->src = src;

[PATCH 06/18] dmaengine: bcm2835: make address increment platform independent

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

Actually the criteria to increment source & destination address doesn't
based on platform specific bits. It's just the DMA transfer direction which
is translated into the info bits. So introduce two new helper functions
and get the rid of these platform specifics.

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 28 ++--
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index ef452ebb3c15..d6c5a2762a46 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -252,6 +252,24 @@ static u32 bcm2835_dma_prepare_cb_extra(struct 
bcm2835_chan *c,
return result;
 }
 
+static inline bool need_src_incr(enum dma_transfer_direction direction)
+{
+   return direction != DMA_DEV_TO_MEM;
+}
+
+static inline bool need_dst_incr(enum dma_transfer_direction direction)
+{
+   switch (direction) {
+   case DMA_MEM_TO_MEM:
+   case DMA_DEV_TO_MEM:
+   return true;
+   default:
+   break;
+   }
+
+   return false;
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
size_t i;
@@ -336,10 +354,8 @@ static inline size_t bcm2835_dma_count_frames_for_sg(
  * @cyclic: it is a cyclic transfer
  * @info:   the default info bits to apply per controlblock
  * @frames: number of controlblocks to allocate
- * @src:the src address to assign (if the S_INC bit is set
- *  in @info, then it gets incremented)
- * @dst:the dst address to assign (if the D_INC bit is set
- *  in @info, then it gets incremented)
+ * @src:the src address to assign
+ * @dst:the dst address to assign
  * @buf_len:the full buffer length (may also be 0)
  * @period_len: the period length when to apply @finalextrainfo
  *  in addition to the last transfer
@@ -408,9 +424,9 @@ static struct bcm2835_desc *bcm2835_dma_create_cb_chain(
d->cb_list[frame - 1].cb->next = cb_entry->paddr;
 
/* update src and dst and length */
-   if (src && (info & BCM2835_DMA_S_INC))
+   if (src && need_src_incr(direction))
src += control_block->length;
-   if (dst && (info & BCM2835_DMA_D_INC))
+   if (dst && need_dst_incr(direction))
dst += control_block->length;
 
/* Length of total transfer */
-- 
2.34.1



[PATCH 05/18] dmaengine: bcm2835: move CB final extra info generation into function

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

Similar to the info generation, generate the final extra info with a
separate function. This is necessary to introduce other platforms
with different info bits.

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 34 --
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 7cef7ff89575..ef452ebb3c15 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -229,6 +229,29 @@ static u32 bcm2835_dma_prepare_cb_info(struct bcm2835_chan 
*c,
return result;
 }
 
+static u32 bcm2835_dma_prepare_cb_extra(struct bcm2835_chan *c,
+   enum dma_transfer_direction direction,
+   bool cyclic, bool final,
+   unsigned long flags)
+{
+   u32 result = 0;
+
+   if (cyclic) {
+   if (flags & DMA_PREP_INTERRUPT)
+   result |= BCM2835_DMA_INT_EN;
+   } else {
+   if (!final)
+   return 0;
+
+   result |= BCM2835_DMA_INT_EN;
+
+   if (direction == DMA_MEM_TO_MEM)
+   result |= BCM2835_DMA_WAIT_RESP;
+   }
+
+   return result;
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
size_t i;
@@ -644,7 +667,8 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_memcpy(
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_desc *d;
u32 info = bcm2835_dma_prepare_cb_info(c, DMA_MEM_TO_MEM, false);
-   u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP;
+   u32 extra = bcm2835_dma_prepare_cb_extra(c, DMA_MEM_TO_MEM, false,
+true, 0);
size_t max_len = bcm2835_dma_max_frame_length(c);
size_t frames;
 
@@ -675,7 +699,7 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_slave_sg(
struct bcm2835_desc *d;
dma_addr_t src = 0, dst = 0;
u32 info = bcm2835_dma_prepare_cb_info(c, direction, false);
-   u32 extra = BCM2835_DMA_INT_EN;
+   u32 extra = bcm2835_dma_prepare_cb_extra(c, direction, false, true, 0);
size_t frames;
 
if (!is_slave_direction(direction)) {
@@ -723,7 +747,7 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_cyclic(
dma_addr_t src, dst;
u32 info = bcm2835_dma_prepare_cb_info(c, direction,
   buf_addr == od->zero_page);
-   u32 extra = 0;
+   u32 extra = bcm2835_dma_prepare_cb_extra(c, direction, true, true, 0);
size_t max_len = bcm2835_dma_max_frame_length(c);
size_t frames;
 
@@ -739,9 +763,7 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_cyclic(
return NULL;
}
 
-   if (flags & DMA_PREP_INTERRUPT)
-   extra |= BCM2835_DMA_INT_EN;
-   else
+   if (!(flags & DMA_PREP_INTERRUPT))
period_len = buf_len;
 
/*
-- 
2.34.1



[PATCH 04/18] dmaengine: bcm2835: move CB info generation into separate function

2024-05-24 Thread Dave Stevenson
From: Stefan Wahren 

Actually the generation of the Control Block info follows some simple
rules. So handle this with a separate function to avoid open coding
for every DMA operation. Another advantage is that we can easier
introduce other platforms with different info bits.

Signed-off-by: Stefan Wahren 
Signed-off-by: Dave Stevenson 
---
 drivers/dma/bcm2835-dma.c | 50 +--
 1 file changed, 32 insertions(+), 18 deletions(-)

diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 528c4593b45a..7cef7ff89575 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -201,6 +201,34 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc(
return container_of(t, struct bcm2835_desc, vd.tx);
 }
 
+static u32 bcm2835_dma_prepare_cb_info(struct bcm2835_chan *c,
+  enum dma_transfer_direction direction,
+  bool zero_page)
+{
+   u32 result;
+
+   if (direction == DMA_MEM_TO_MEM)
+   return BCM2835_DMA_D_INC | BCM2835_DMA_S_INC;
+
+   result = BCM2835_DMA_WAIT_RESP;
+
+   /* Setup DREQ channel */
+   if (c->dreq != 0)
+   result |= BCM2835_DMA_PER_MAP(c->dreq);
+
+   if (direction == DMA_DEV_TO_MEM) {
+   result |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
+   } else {
+   result |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
+
+   /* non-lite channels can write zeroes w/o accessing memory */
+   if (zero_page && !c->is_lite_channel)
+   result |= BCM2835_DMA_S_IGNORE;
+   }
+
+   return result;
+}
+
 static void bcm2835_dma_free_cb_chain(struct bcm2835_desc *desc)
 {
size_t i;
@@ -615,7 +643,7 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_memcpy(
 {
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_desc *d;
-   u32 info = BCM2835_DMA_D_INC | BCM2835_DMA_S_INC;
+   u32 info = bcm2835_dma_prepare_cb_info(c, DMA_MEM_TO_MEM, false);
u32 extra = BCM2835_DMA_INT_EN | BCM2835_DMA_WAIT_RESP;
size_t max_len = bcm2835_dma_max_frame_length(c);
size_t frames;
@@ -646,7 +674,7 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_slave_sg(
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_desc *d;
dma_addr_t src = 0, dst = 0;
-   u32 info = BCM2835_DMA_WAIT_RESP;
+   u32 info = bcm2835_dma_prepare_cb_info(c, direction, false);
u32 extra = BCM2835_DMA_INT_EN;
size_t frames;
 
@@ -656,19 +684,14 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_slave_sg(
return NULL;
}
 
-   if (c->dreq != 0)
-   info |= BCM2835_DMA_PER_MAP(c->dreq);
-
if (direction == DMA_DEV_TO_MEM) {
if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
return NULL;
src = c->cfg.src_addr;
-   info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
} else {
if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
return NULL;
dst = c->cfg.dst_addr;
-   info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
}
 
/* count frames in sg list */
@@ -698,7 +721,8 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_cyclic(
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_desc *d;
dma_addr_t src, dst;
-   u32 info = BCM2835_DMA_WAIT_RESP;
+   u32 info = bcm2835_dma_prepare_cb_info(c, direction,
+  buf_addr == od->zero_page);
u32 extra = 0;
size_t max_len = bcm2835_dma_max_frame_length(c);
size_t frames;
@@ -729,26 +753,16 @@ static struct dma_async_tx_descriptor 
*bcm2835_dma_prep_dma_cyclic(
  "%s: buffer_length (%zd) is not a multiple of 
period_len (%zd)\n",
  __func__, buf_len, period_len);
 
-   /* Setup DREQ channel */
-   if (c->dreq != 0)
-   info |= BCM2835_DMA_PER_MAP(c->dreq);
-
if (direction == DMA_DEV_TO_MEM) {
if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
return NULL;
src = c->cfg.src_addr;
dst = buf_addr;
-   info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
} else {
if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
return NULL;
dst = c->cfg.dst_addr;
src = buf_addr;
-   info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
-
-   /* non-lite channels can write zeroes w/o accessing memory */
-   if (buf_addr == od->zero_page &&a

[PATCH 01/18] dma-direct: take dma-ranges/offsets into account in resource mapping

2024-05-24 Thread Dave Stevenson
From: Serge Semin 

A basic device-specific linear memory mapping was introduced back in
commit ("dma: Take into account dma_pfn_offset") as a single-valued offset
preserved in the device.dma_pfn_offset field, which was initialized for
instance by means of the "dma-ranges" DT property. Afterwards the
functionality was extended to support more than one device-specific region
defined in the device.dma_range_map list of maps. But all of these
improvements concerned a single pointer, page or sg DMA-mapping methods,
while the system resource mapping function turned to miss the
corresponding modification. Thus the dma_direct_map_resource() method now
just casts the CPU physical address to the device DMA address with no
dma-ranges-based mapping taking into account, which is obviously wrong.
Let's fix it by using the phys_to_dma_direct() method to get the
device-specific bus address from the passed memory resource for the case
of the directly mapped DMA.

Fixes: 25f1e1887088 ("dma: Take into account dma_pfn_offset")
Signed-off-by: Serge Semin 
Signed-off-by: Dave Stevenson 
---
 kernel/dma/direct.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 4d543b1e9d57..916a16959575 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -509,7 +509,7 @@ int dma_direct_map_sg(struct device *dev, struct 
scatterlist *sgl, int nents,
 dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-   dma_addr_t dma_addr = paddr;
+   dma_addr_t dma_addr = phys_to_dma_direct(dev, paddr);
 
if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
dev_err_once(dev,
-- 
2.34.1



[PATCH 03/18] ARM: dts: bcm283x: Update to use dma-channel-mask

2024-05-24 Thread Dave Stevenson
Now the driver looks for the common dma-channel-mask property
rather than the vendor-specific brcm,dma-channel-mask, update
the dt files to follow suit.

Signed-off-by: Dave Stevenson 
---
 arch/arm/boot/dts/broadcom/bcm2711.dtsi| 2 +-
 arch/arm/boot/dts/broadcom/bcm2835-common.dtsi | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/broadcom/bcm2711.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
index e4e42af21ef3..d64bf098b697 100644
--- a/arch/arm/boot/dts/broadcom/bcm2711.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2711.dtsi
@@ -103,7 +103,7 @@ dma: dma-controller@7e007000 {
  "dma9",
  "dma10";
#dma-cells = <1>;
-   brcm,dma-channel-mask = <0x07f5>;
+   dma-channel-mask = <0x07f5>;
};
 
pm: watchdog@7e10 {
diff --git a/arch/arm/boot/dts/broadcom/bcm2835-common.dtsi 
b/arch/arm/boot/dts/broadcom/bcm2835-common.dtsi
index 9261b67dbee1..3ba8db8eed0f 100644
--- a/arch/arm/boot/dts/broadcom/bcm2835-common.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm2835-common.dtsi
@@ -46,7 +46,7 @@ dma: dma-controller@7e007000 {
  "dma14",
  "dma-shared-all";
#dma-cells = <1>;
-   brcm,dma-channel-mask = <0x7f35>;
+   dma-channel-mask = <0x7f35>;
};
 
intc: interrupt-controller@7e00b200 {
-- 
2.34.1



Re: UAPI Re: [PATCH 1/3] drm: Add DRM_MODE_TV_MODE_MONOCHROME

2024-02-26 Thread Dave Stevenson
Hi Pekka

Sorry for the slight delay in replying.

On Mon, 26 Feb 2024 at 15:11, Pekka Paalanen
 wrote:
>
> On Mon, 26 Feb 2024 15:10:45 +0100
> Maxime Ripard  wrote:
>
> > Hi Pekka,
> >
> > On Wed, Feb 21, 2024 at 11:07:51AM +0200, Pekka Paalanen wrote:
> > > On Fri, 16 Feb 2024 18:48:55 +
> > > Dave Stevenson  wrote:
> > >
> > > > From: Nick Hollinghurst 
> > > >
> > > > Add this as a value for enum_drm_connector_tv_mode, represented
> > > > by the string "Mono", to generate video with no colour encoding
> > > > or bursts. Define it to have no pedestal (since only NTSC-M calls
> > > > for a pedestal).
> > > >
> > > > Change default mode creation to acommodate the new tv_mode value
> > > > which comprises both 525-line and 625-line formats.
> > > >
> > > > Signed-off-by: Nick Hollinghurst 
> > > > Signed-off-by: Dave Stevenson 
> > >
> > > since no-one else commented yet, I'd like to remind of the new UAPI
> > > requirements:
> > > https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#open-source-userspace-requirements
> > >
> > > AFAIU, adding a new value to an existing enum still counts as new UAPI.
> > >
> > > Maybe there is no need for the full treatment here, or maybe there is,
> > > I'm not sure. I think you should make some statement about how the new
> > > UAPI requirements have been addressed.
> >
> > That property was meant to provide legacy display handling, so I don't
> > expect any reasonably recent codebase like Weston to suppport it, ever
> > :)
> >
> > That being said, from the beginning, that property was meant to be
> > handled as a "mode-setting" property, and thus handled by either the
> > kernel command-line, xrandr, or any similar mechanism.
> >
> > I would expect that new enum variant to be handled under the same terms:
> > it'll probably only show up in distro scripts or configuration files,
> > and never in any actual code base.
> >
> > Is it what you were expecting, or did you mean something else?
>
> Maybe? Let's have it in the commit message and see if DRM maintainers
> agree.

You want the commit text for a patch adding a new enum to state that
the whole property isn't expected to be used through the UAPI? OK, I
can roll a v2 if that is your desire.

> You should expect that all KMS clients will work towards programming
> all exposed KMS properties into known values. That's the only way to
> achieve repeatable KMS behaviour, because there is no KMS reset ioctl.
>
> There are no two tiers of KMS properties AFAIK. You have to be the DRM
> master to change anything. So, people cannot force any settings from
> outside of a KMS client, they have to go through the KMS client, like
> xrandr goes through Xorg (and only Xorg).
>
> I do fully expect Weston to gain support for this property, if anyone
> cares of its value. That goes for all Wayland compositors.

I don't know about Weston, but Wayfire / wlroots / sway have currently
chosen to ignore all interlaced display modes [1].
[2] is the wlroots devs basically calling interlaced output a dead end.

That makes the debate for controlling the colour encoding on a
composite video rather redundant as they're almost always interlaced.

[1] https://github.com/swaywm/sway/issues/3167
[2] https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3038

> You're correct in that a KMS client would probably not know to control
> the value of this property automatically but it needs to come from
> configuration. That would be each KMS client's configuration. I don't
> understand how a script could achieve that.
>
> However, if you feel it is important to have KMS properties that
> display servers must not touch, then they should be documented as such.
> I do not know if that would actually lift the new-UAPI requirements,
> that is for the DRM maintainers to decide and document. Is there such a
> thing already?
>
> What are those "similar to xrandr" mechanisms? I don't think I've heard
> of any,

Boot to the console and run
modetest -w :"tv_mode":"NTSC"
There is no reset mechanism for all properties, so that setting
persists after modetest quits.

> and I've also completely missed any kernel command line
> arguments manipulating KMS properties.

"tv_mode" on the command line is handled in
drm_mode_parse_cmdline_options() [3], as are rotate, reflect_x,
reflect_y, margin_[left|right|top|bottom], and panel_orientation all
to set the relevant KMS properties.

Having "video=Composite-1:PAL,tv_mode=Mono" on the kernel comm

Re: [PATCH] drm/edid/firmware: Remove built-in EDIDs

2024-02-20 Thread Dave Stevenson
Hi Maxime

On Tue, 20 Feb 2024 at 16:10, Maxime Ripard  wrote:
>
> The EDID firmware loading mechanism introduced a few built-in EDIDs that
> could be forced on any connector, bypassing the EDIDs it exposes.
>
> While convenient, this limited set of EDIDs doesn't take into account
> the connector type, and we can end up with an EDID that is completely
> invalid for a given connector.
>
> For example, the edid/800x600.bin file matches the following EDID:
>
>   edid-decode (hex):
>
>   00 ff ff ff ff ff ff 00 31 d8 00 00 00 00 00 00
>   05 16 01 03 6d 1b 14 78 ea 5e c0 a4 59 4a 98 25
>   20 50 54 01 00 00 45 40 01 01 01 01 01 01 01 01
>   01 01 01 01 01 01 a0 0f 20 00 31 58 1c 20 28 80
>   14 00 15 d0 10 00 00 1e 00 00 00 ff 00 4c 69 6e
>   75 78 20 23 30 0a 20 20 20 20 00 00 00 fd 00 3b
>   3d 24 26 05 00 0a 20 20 20 20 20 20 00 00 00 fc
>   00 4c 69 6e 75 78 20 53 56 47 41 0a 20 20 00 c2
>
>   
>
>   Block 0, Base EDID:
> EDID Structure Version & Revision: 1.3
> Vendor & Product Identification:
>   Manufacturer: LNX
>   Model: 0
>   Made in: week 5 of 2012
> Basic Display Parameters & Features:
>   Analog display
>   Signal Level Standard: 0.700 : 0.000 : 0.700 V p-p
>   Blank level equals black level
>   Sync: Separate Composite Serration
>   Maximum image size: 27 cm x 20 cm
>   Gamma: 2.20
>   DPMS levels: Standby Suspend Off
>   RGB color display
>   First detailed timing is the preferred timing
> Color Characteristics:
>   Red  : 0.6416, 0.3486
>   Green: 0.2919, 0.5957
>   Blue : 0.1474, 0.1250
>   White: 0.3125, 0.3281
> Established Timings I & II:
>   DMT 0x09:   800x60060.316541 Hz   4:3 37.879 kHz 40.00 
> MHz
> Standard Timings:
>   DMT 0x09:   800x60060.316541 Hz   4:3 37.879 kHz 40.00 
> MHz
> Detailed Timing Descriptors:
>   DTD 1:   800x60060.316541 Hz   4:3 37.879 kHz 40.00 MHz 
> (277 mm x 208 mm)
>Hfront   40 Hsync 128 Hback   88 Hpol P
>Vfront1 Vsync   4 Vback   23 Vpol P
>   Display Product Serial Number: 'Linux #0'
>   Display Range Limits:
> Monitor ranges (GTF): 59-61 Hz V, 36-38 kHz H, max dotclock 50 MHz
>   Display Product Name: 'Linux SVGA'
>   Checksum: 0xc2
>
> So, an analog monitor EDID. However, if the connector was an HDMI
> monitor for example, it breaks the HDMI specification that requires,
> among other things, a digital display, the VIC 1 mode and an HDMI Forum
> Vendor Specific Data Block in an CTA-861 extension.
>
> We thus end up with a completely invalid EDID, which thus might confuse
> HDMI-related code that could parse it.
>
> After some discussions on IRC, we identified mainly two ways to fix
> this:
>
>   - We can either create more EDIDs for each connector type to provide
> a built-in EDID that matches the resolution passed in the name, and
> still be a sensible EDID for that connector type;
>
>   - Or we can just prevent the EDID to be exposed to userspace if it's
> built-in.
>
> Or possibly both.
>
> However, the conclusion was that maybe we just don't need the built-in
> EDIDs at all and we should just get rid of them. So here we are.
>
> Signed-off-by: Maxime Ripard 
> ---
>  drivers/gpu/drm/drm_edid_load.c | 160 +++-

Needs to be removed from the docs too:

"The code (see drivers/gpu/drm/drm_edid_load.c) contains built-in data
sets for commonly used screen resolutions (800x600, 1024x768,
1280x1024, 1600x1200, 1680x1050, 1920x1080) as binary blobs,..."

https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/edid.rst

I'm sad to see these go, but c'est la vie. Descriptions of using these
built in EDIDs abound in various tutorials, so those are all now
invalid :/

  Dave

>  1 file changed, 13 insertions(+), 147 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_edid_load.c b/drivers/gpu/drm/drm_edid_load.c
> index 60fcb80bce61..d1c7e8298702 100644
> --- a/drivers/gpu/drm/drm_edid_load.c
> +++ b/drivers/gpu/drm/drm_edid_load.c
> @@ -20,162 +20,28 @@
>
>  static char edid_firmware[PATH_MAX];
>  module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 
> 0644);
> -MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID 
> blob "
> -   "from built-in data or /lib/firmware instead. ");
> -
> -#define GENERIC_EDIDS 6
> -static const char * const generic_edid_name[GENERIC_EDIDS] = {
> -   "edid/800x600.bin",
> -   "edid/1024x768.bin",
> -   "edid/1280x1024.bin",
> -   "edid/1600x1200.bin",
> -   "edid/1680x1050.bin",
> -   "edid/1920x1080.bin",
> -};
> -
> -static const u8 generic_edid[GENERIC_EDIDS][128] = {
> -   {
> -   0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
> -   0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> -   0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
> -   0xea, 0x5e, 0xc0, 

[PATCH 3/3] drm/vc4: vec: Add the margin properties to the connector

2024-02-16 Thread Dave Stevenson
All the handling for the properties was present, but they
were never attached to the connector to allow userspace
to change them.

Add them to the connector.

Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/vc4/vc4_vec.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index f9e134dd1e3b..0aed18920d18 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -528,6 +528,8 @@ static int vc4_vec_connector_init(struct drm_device *dev, 
struct vc4_vec *vec)
 
drm_object_attach_property(>base, prop, 
VC4_VEC_TV_MODE_NTSC);
 
+   drm_connector_attach_tv_margin_properties(connector);
+
drm_connector_attach_encoder(connector, >encoder.base);
 
return 0;
-- 
2.25.1



[PATCH 2/3] drm/vc4: Add monochrome mode to the VEC.

2024-02-16 Thread Dave Stevenson
The VEC supports not producing colour bursts for monochrome output.
It also has an option for disabling the chroma input to remove
chroma from the signal.

Now that there is a DRM_MODE_TV_MODE_MONOCHROME defined, plumb
this in.

Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/vc4/vc4_vec.c | 28 +++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index 268f18b10ee0..f9e134dd1e3b 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -234,6 +234,7 @@ enum vc4_vec_tv_mode_id {
VC4_VEC_TV_MODE_PAL_60,
VC4_VEC_TV_MODE_PAL_N,
VC4_VEC_TV_MODE_SECAM,
+   VC4_VEC_TV_MODE_MONOCHROME,
 };
 
 struct vc4_vec_tv_mode {
@@ -324,6 +325,22 @@ static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
.config1 = VEC_CONFIG1_C_CVBS_CVBS,
.custom_freq = 0x29c71c72,
},
+   {
+   /* 50Hz mono */
+   .mode = DRM_MODE_TV_MODE_MONOCHROME,
+   .expected_htotal = 864,
+   .config0 = VEC_CONFIG0_PAL_BDGHI_STD | VEC_CONFIG0_BURDIS |
+  VEC_CONFIG0_CHRDIS,
+   .config1 = VEC_CONFIG1_C_CVBS_CVBS,
+   },
+   {
+   /* 60Hz mono */
+   .mode = DRM_MODE_TV_MODE_MONOCHROME,
+   .expected_htotal = 858,
+   .config0 = VEC_CONFIG0_PAL_M_STD | VEC_CONFIG0_BURDIS |
+  VEC_CONFIG0_CHRDIS,
+   .config1 = VEC_CONFIG1_C_CVBS_CVBS,
+   },
 };
 
 static inline const struct vc4_vec_tv_mode *
@@ -351,6 +368,7 @@ static const struct drm_prop_enum_list 
legacy_tv_mode_names[] = {
{ VC4_VEC_TV_MODE_PAL_M, "PAL-M", },
{ VC4_VEC_TV_MODE_PAL_N, "PAL-N", },
{ VC4_VEC_TV_MODE_SECAM, "SECAM", },
+   { VC4_VEC_TV_MODE_MONOCHROME, "Mono", },
 };
 
 static enum drm_connector_status
@@ -406,6 +424,10 @@ vc4_vec_connector_set_property(struct drm_connector 
*connector,
state->tv.mode = DRM_MODE_TV_MODE_SECAM;
break;
 
+   case VC4_VEC_TV_MODE_MONOCHROME:
+   state->tv.mode = DRM_MODE_TV_MODE_MONOCHROME;
+   break;
+
default:
return -EINVAL;
}
@@ -453,6 +475,9 @@ vc4_vec_connector_get_property(struct drm_connector 
*connector,
*val = VC4_VEC_TV_MODE_SECAM;
break;
 
+   case DRM_MODE_TV_MODE_MONOCHROME:
+   return VC4_VEC_TV_MODE_MONOCHROME;
+
default:
return -EINVAL;
}
@@ -754,7 +779,8 @@ static int vc4_vec_bind(struct device *dev, struct device 
*master, void *data)
BIT(DRM_MODE_TV_MODE_PAL) |
BIT(DRM_MODE_TV_MODE_PAL_M) |
BIT(DRM_MODE_TV_MODE_PAL_N) |
-   BIT(DRM_MODE_TV_MODE_SECAM));
+   BIT(DRM_MODE_TV_MODE_SECAM) |
+   BIT(DRM_MODE_TV_MODE_MONOCHROME));
if (ret)
return ret;
 
-- 
2.25.1



[PATCH 1/3] drm: Add DRM_MODE_TV_MODE_MONOCHROME

2024-02-16 Thread Dave Stevenson
From: Nick Hollinghurst 

Add this as a value for enum_drm_connector_tv_mode, represented
by the string "Mono", to generate video with no colour encoding
or bursts. Define it to have no pedestal (since only NTSC-M calls
for a pedestal).

Change default mode creation to acommodate the new tv_mode value
which comprises both 525-line and 625-line formats.

Signed-off-by: Nick Hollinghurst 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/drm_connector.c| 7 +++
 drivers/gpu/drm/drm_modes.c| 5 -
 drivers/gpu/drm/drm_probe_helper.c | 5 +++--
 include/drm/drm_connector.h| 7 +++
 4 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index b0516505f7ae..fe05d27f3404 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -1005,6 +1005,7 @@ static const struct drm_prop_enum_list 
drm_tv_mode_enum_list[] = {
{ DRM_MODE_TV_MODE_PAL_M, "PAL-M" },
{ DRM_MODE_TV_MODE_PAL_N, "PAL-N" },
{ DRM_MODE_TV_MODE_SECAM, "SECAM" },
+   { DRM_MODE_TV_MODE_MONOCHROME, "Mono" },
 };
 DRM_ENUM_NAME_FN(drm_get_tv_mode_name, drm_tv_mode_enum_list)
 
@@ -1697,6 +1698,12 @@ 
EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
  * TV Mode is CCIR System B (aka 625-lines) together with
  * the SECAM Color Encoding.
  *
+ * Mono:
+ *
+ * Use timings appropriate to the DRM mode, including
+ * equalizing pulses for a 525-line or 625-line mode,
+ * with no pedestal or color encoding.
+ *
  * Drivers can set up this property by calling
  * drm_mode_create_tv_properties().
  */
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index c4f88c3a93b7..d274e7b00b79 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -530,7 +530,8 @@ static int fill_analog_mode(struct drm_device *dev,
  * @interlace: whether to compute an interlaced mode
  *
  * This function creates a struct drm_display_mode instance suited for
- * an analog TV output, for one of the usual analog TV mode.
+ * an analog TV output, for one of the usual analog TV modes. Where
+ * this is DRM_MODE_TV_MODE_MONOCHROME, a 625-line mode will be created.
  *
  * Note that @hdisplay is larger than the usual constraints for the PAL
  * and NTSC timings, and we'll choose to ignore most timings constraints
@@ -568,6 +569,8 @@ struct drm_display_mode *drm_analog_tv_mode(struct 
drm_device *dev,
case DRM_MODE_TV_MODE_PAL_N:
fallthrough;
case DRM_MODE_TV_MODE_SECAM:
+   fallthrough;
+   case DRM_MODE_TV_MODE_MONOCHROME:
analog = DRM_MODE_ANALOG_PAL;
break;
 
diff --git a/drivers/gpu/drm/drm_probe_helper.c 
b/drivers/gpu/drm/drm_probe_helper.c
index d1e1ade66f81..9254dc2af873 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -1211,8 +1211,9 @@ int drm_connector_helper_tv_get_modes(struct 
drm_connector *connector)
for (i = 0; i < tv_mode_property->num_values; i++)
supported_tv_modes |= BIT(tv_mode_property->values[i]);
 
-   if ((supported_tv_modes & ntsc_modes) &&
-   (supported_tv_modes & pal_modes)) {
+   if (((supported_tv_modes & ntsc_modes) &&
+(supported_tv_modes & pal_modes)) ||
+   (supported_tv_modes & BIT(DRM_MODE_TV_MODE_MONOCHROME))) {
uint64_t default_mode;
 
if (drm_object_property_get_default_value(>base,
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index fe88d7fc6b8f..90fd0ea0ca09 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -200,6 +200,13 @@ enum drm_connector_tv_mode {
 */
DRM_MODE_TV_MODE_SECAM,
 
+   /**
+* @DRM_MODE_TV_MODE_MONOCHROME: Use timings appropriate to
+* the DRM mode, including equalizing pulses for a 525-line
+* or 625-line mode, with no pedestal or color encoding.
+*/
+   DRM_MODE_TV_MODE_MONOCHROME,
+
/**
 * @DRM_MODE_TV_MODE_MAX: Number of analog TV output modes.
 *
-- 
2.25.1



[PATCH 0/3] vc4 VEC (analogue video) updates - margins and monochrome

2024-02-16 Thread Dave Stevenson
Hi All

A couple of patches to vc4, including adding a new "TV mode" enum for monochrome
output (yes we have some users who wish for monochrome).

Adding mono has raised a query here as to whether the the TV_MODE is meant to
describe the timing, or just the colour encoding.

The description for NTSC references "CCIR System M (aka 525-lines)", and PAL
references "CCIR System B" which is the 625 line standard.

PAL-60 is absent from the enum, but support has been added to vc4 by selecting 
DRM_MODE_TV_MODE_PAL but with the NTSC (CCIR System M) timings. Is that the
correct implementation? In which case the description for PAL should drop the
CCIR System B reference as selecting the "TV mode" doesn't dictate the timing.

Monochrome is in the same boat as it can adopt either 525 or 625 line timing,
or indeed anything else. Pi5 can support System A 405-line and the French
819-line mono modes as well.

If "TV mode" does dictate the timing as well as the colour encoding, then we
need to add PAL-60, and 2 modes for mono (extending to 4 for 405 and 819 line
modes later). If not, we ought to update the description.

Thoughts?

Thanks
  Dave

Dave Stevenson (2):
  drm/vc4: Add monochrome mode to the VEC.
  drm/vc4: vec: Add the margin properties to the connector

Nick Hollinghurst (1):
  drm: Add DRM_MODE_TV_MODE_MONOCHROME

 drivers/gpu/drm/drm_connector.c|  7 +++
 drivers/gpu/drm/drm_modes.c|  5 -
 drivers/gpu/drm/drm_probe_helper.c |  5 +++--
 drivers/gpu/drm/vc4/vc4_vec.c  | 30 +-
 include/drm/drm_connector.h|  7 +++
 5 files changed, 50 insertions(+), 4 deletions(-)

-- 
2.25.1



Re: Re: [PATCH v5 15/44] drm/connector: hdmi: Compute bpc and format automatically

2024-02-01 Thread Dave Stevenson
Hi Maxime

On Thu, 1 Feb 2024 at 12:51, Maxime Ripard  wrote:
>
> On Thu, Dec 14, 2023 at 03:10:43PM +, Dave Stevenson wrote:
> > > +static bool
> > > +sink_supports_format_bpc(const struct drm_connector *connector,
> > > +const struct drm_display_info *info,
> > > +const struct drm_display_mode *mode,
> > > +unsigned int format, unsigned int bpc)
> > > +{
> > > +   struct drm_device *dev = connector->dev;
> > > +   u8 vic = drm_match_cea_mode(mode);
> > > +
> > > +   if (vic == 1 && bpc != 8) {
> > > +   drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
> > > +   return false;
> > > +   }
> > > +
> > > +   if (!info->is_hdmi &&
> > > +   (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
> > > +   drm_dbg(dev, "DVI Monitors require an RGB output at 8 
> > > bpc\n");
> > > +   return false;
> > > +   }
> > > +
> > > +   if (!(connector->hdmi.supported_formats & BIT(format))) {
> > > +   drm_dbg(dev, "%s format unsupported by the connector.\n",
> > > +   
> > > drm_hdmi_connector_get_output_format_name(format));
> > > +   return false;
> > > +   }
> > > +
> > > +   switch (format) {
> > > +   case HDMI_COLORSPACE_RGB:
> > > +   drm_dbg(dev, "RGB Format, checking the constraints.\n");
> > > +
> > > +   if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
> > > +   return false;
> >
> > We've dropped this check from vc4 in our downstream kernel as it stops
> > you using the prebaked EDIDs (eg drm.edid_firmware=edid/1024x768.bin),
> > or any other EDID that is defined as an analog monitor.
> > The EDID parsing bombs out at [1], so info->color_formats gets left at 0.
>
> Right, but it only does so if the display isn't defined as a digital 
> display...
>
> > RGB is mandatory for both DVI and HDMI, so rejecting it seems overly fussy.
>
> ... which is required for both DVI and HDMI.
>
> And sure enough, if we decode that EDID:
>
> edid-decode (hex):
>
> 00 ff ff ff ff ff ff 00 31 d8 00 00 00 00 00 00
> 05 16 01 03 6d 23 1a 78 ea 5e c0 a4 59 4a 98 25
> 20 50 54 00 08 00 61 40 01 01 01 01 01 01 01 01
> 01 01 01 01 01 01 64 19 00 40 41 00 26 30 08 90
> 36 00 63 0a 11 00 00 18 00 00 00 ff 00 4c 69 6e
> 75 78 20 23 30 0a 20 20 20 20 00 00 00 fd 00 3b
> 3d 2f 31 07 00 0a 20 20 20 20 20 20 00 00 00 fc
> 00 4c 69 6e 75 78 20 58 47 41 0a 20 20 20 00 55
>
> 
>
> Block 0, Base EDID:
>   EDID Structure Version & Revision: 1.3
>   Vendor & Product Identification:
> Manufacturer: LNX
> Model: 0
> Made in: week 5 of 2012
>   Basic Display Parameters & Features:
> Analog display
> Signal Level Standard: 0.700 : 0.000 : 0.700 V p-p
> Blank level equals black level
> Sync: Separate Composite Serration
> Maximum image size: 35 cm x 26 cm
> Gamma: 2.20
> DPMS levels: Standby Suspend Off
> RGB color display
> First detailed timing is the preferred timing
>   Color Characteristics:
> Red  : 0.6416, 0.3486
> Green: 0.2919, 0.5957
> Blue : 0.1474, 0.1250
> White: 0.3125, 0.3281
>   Established Timings I & II:
> DMT 0x10:  1024x76860.003840 Hz   4:3 48.363 kHz 65.00 MHz
>   Standard Timings:
> DMT 0x10:  1024x76860.003840 Hz   4:3 48.363 kHz 65.00 MHz
>   Detailed Timing Descriptors:
> DTD 1:  1024x76860.003840 Hz   4:3 48.363 kHz 65.00 MHz 
> (355 mm x 266 mm)
>  Hfront8 Hsync 144 Hback  168 Hpol N
>  Vfront3 Vsync   6 Vback   29 Vpol N
> Display Product Serial Number: 'Linux #0'
> Display Range Limits:
>   Monitor ranges (GTF): 59-61 Hz V, 47-49 kHz H, max dotclock 70 MHz
> Display Product Name: 'Linux XGA'
> Checksum: 0x55
>
> 
>
> Warnings:
>
> Block 0, Base EDID:
>   Detailed Timing Descriptor #1: DTD is similar but not identical to DMT 0x10.
>
> EDID conformity: PASS
>
> So, if anything, it's the EDID that needs to be updated, not the code there.

So are these EDIDs only valid for VGA outputs and another set needs to
be added for HDMI monitors?

Having drm.edid_firmware=edid/1024x768.bin works on an HDMI connector
prior to this patch, so presumably drm_edid_loader needs to
automatically switch between the existing (analog) and new (digital)
EDIDs based on the connector type? Or are you requiring users to
change the strings they use?

Cheers.
  Dave


Re: drm: Stable identification of connectors?

2024-01-26 Thread Dave Stevenson
Hi Joerg

On Fri, 26 Jan 2024 at 10:45, Albert, Joerg (TT-U) 
wrote:

> Hi,
>
>
>
> I’m pretty new to DRM/DRI and wonder if there is a way to have a stable
> identification of connectors across changes in the Linux kernel and/or in
> the devicetree?
>
>
>
> Our hardware contains an iMX8QM with two displays, each one connected to a
> MIPI-DSI channel. We use kernel 6.1.38.
>
> In the output of “modetest -c” the connectors are called LVDS-1 and
> LVDS-2. These names are built in modetest.c from connector_type and
> connector_type_id.
>
>
>
> connector_type_id is set in the kernel in drivers/gpu/drm/drm_connector.c
> in __drm_connector_init():
>
>
>
>*connector* 
> ->*connector_type_id*
>   =
>
>   *ida_alloc_min* 
> (*connector_ida*
>  , 1, 
> *GFP_KERNEL* );
>
>
>
> Seems to me that this number depends on initialization order only. Is
> there any other way to identify a connector?
>
>
>
> If not, will the type_id be stable as long as we don’t change the kernel
> version and the device tree?
>

My understanding is it all depends on initialisation order, and that isn't
guaranteed.

Raspberry Pi 5 has a similar issue that it has two independent DRM driver
instances each initialising a DSI connector. Which one gets assigned DSI-1
vs DSI-2 is down to probe order, and can change between boots.
You also have the situation that a panel connected to the second connector
is referred to as DSI-1 if nothing is connected to the first, but it'll
probably bump up to DSI-2 should you later configure a panel on the first
connector. Any configuration within a window manager based on display ID is
therefore near useless if there is any change to the system.

It's the same situation if you have more than one SPI display using the
mipi-dbi-spi or tinyDRM drivers - ordering of display to SPI-x IDs is down
to probe order, so near random.

I haven't attempted to upstream this yet, but on our tree [1] I've adopted
the same approach as the I2C and SPI subsystems take where a DT alias can
be used to set the desired connector ID. Devices with no alias get assigned
IDs above the last assigned alias.

Seeing as you've raised the same issue, it'd be interesting to know the
view of the maintainers as to whether my solution is acceptable. There's no
point in trying to upstream it if it's going to be immediately shot down.

Thanks.
  Dave

[1]
https://github.com/raspberrypi/linux/commit/3aa1f2477545ea6298bc6f2d7ffae68f090af9b8
and fixup
https://github.com/raspberrypi/linux/commit/f429fc1a072d4bb35e622a1012a5a52914eba4e3


>
> Best Regards,
>
> Joerg Albert
>
>
>
>
>
>
>
>
>
>
>
>
> +491747384960
>
>
>
>
> We move the world for the better through technology and engineering.
>
> www.iav.com | Facebook  | Instagram
>  | LinkedIn
>  | Xing
>  | YouTube
> 
>
> IAV GmbH Ingenieurgesellschaft Auto und Verkehr; Sitz/Registered Office:
> Berlin; Registergericht/Registration Court: Amtsgericht Charlottenburg
> (Berlin); Registernummer/Company Registration Number: HRB 21 280 B;
> Geschäftsführer/Managing Directors: Joerg Astalosch, Martin Mahlke, Dr. Uwe
> Horn; Vorsitzender des Aufsichtsrates/Chairman of the Supervisory Board:
> Dr. Nikolai Ardey
> Datenschutzhinweise/Privacy Policy 
>
>
>


Re: [PATCH v5 08/44] drm/connector: hdmi: Add Broadcast RGB property

2024-01-12 Thread Dave Stevenson
Hi Maxime

On Fri, 12 Jan 2024 at 13:59, Maxime Ripard  wrote:
>
> Hi Dave,
>
> On Thu, Dec 14, 2023 at 02:43:37PM +, Dave Stevenson wrote:
> > On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
> > >
> > > The i915 driver has a property to force the RGB range of an HDMI output.
> > > The vc4 driver then implemented the same property with the same
> > > semantics. KWin has support for it, and a PR for mutter is also there to
> > > support it.
> > >
> > > Both drivers implementing the same property with the same semantics,
> > > plus the userspace having support for it, is proof enough that it's
> > > pretty much a de-facto standard now and we can provide helpers for it.
> > >
> > > Let's plumb it into the newly created HDMI connector.
> >
> > To have such a significant proportion of the patch being kunit tests
> > when there was no reference to such in the commit text was slightly
> > unexpected.
>
> Thanks for your review. Does that mean that you would prefer the tests
> to be in a separate patch?

If there was a need for a respin, then I think ideally yes, or at
least a mention in the commit text ("Let's plumb it into the newly
created HDMI connector*, and add appropriate unit tests*").
Overall I'm not that fussed though.

  Dave


Re: [PATCH v2 0/2] Add waveshare 7inch touchscreen panel support

2024-01-09 Thread Dave Stevenson
Hi

On Tue, 9 Jan 2024 at 11:19,  wrote:
>
> Hi,
>
> On 09/01/2024 08:09, Shengyang Chen wrote:
> > This patchset adds waveshare 7inch touchscreen panel support
> > for the StarFive JH7110 SoC.
>
> Could you precise which SKU you're referring to ? is it 19885 => 
> https://www.waveshare.com/7inch-dsi-lcd.htm ?
>
> Are you sure it requires different timings from the RPi one ? In the Waveshare
> wiki it explicitly uses the rpi setup (vc4-kms-dsi-7inch) to drive it: 
> https://www.waveshare.com/wiki/7inch_DSI_LCD

I raise the same question.

Keith Zhao earlier submitted effectively the same set of patches [1]
and the response for the updated timing was:

My platform dphy tx hardware has certain limitations.
Only supports integer multiples of 10M bitrate:
such as 160M ,170M, 180M,190M,...1G(max)

as common dphy bitrate = pixclock*bpp/lanes.
This value cannot match successfully in most cases.

so in order to match bitrate , I choose a bitrate value around
pixclock*bpp/lanes,
Prevent overflow and underflow by fine-tuning the timing parameters:-(
that will make the new timming value.


I then suggested mode_fixup should be used in the DSI host driver, and
Keith acknowledged that.

Is this new timing still because of the DSI host requirement?

  Dave

[1] https://lists.freedesktop.org/archives/dri-devel/2023-December/434150.html

> Neil
>
> >
> >
> > changes since v1:
> > - Rebased on tag v6.7.
> >
> > patch 1:
> > - Gave up original changing.
> > - Changed the commit message.
> > - Add compatible in panel-simple.yaml
> >
> > patch 2:
> > - Gave up original changing.
> > - Changed the commit message.
> > - Add new mode for the panel in panel-simple.c
> >
> > v1: 
> > https://patchwork.kernel.org/project/dri-devel/cover/20231124104451.44271-1-shengyang.c...@starfivetech.com/
> >
> > Shengyang Chen (2):
> >dt-bindings: display: panel: panel-simple: Add compatible property for
> >  waveshare 7inch touchscreen panel
> >gpu: drm: panel: panel-simple: add new display mode for waveshare
> >  7inch touchscreen panel
> >
> >   .../bindings/display/panel/panel-simple.yaml  |  2 ++
> >   drivers/gpu/drm/panel/panel-simple.c  | 28 +++
> >   2 files changed, 30 insertions(+)
> >
>


Re: [PATCH v9 09/25] drm/modes: Move named modes parsing to a separate function

2024-01-03 Thread Dave Stevenson
On Wed, 3 Jan 2024 at 14:02, Dave Stevenson
 wrote:
>
> Hi Maxime
>
> On Wed, 3 Jan 2024 at 13:33, Maxime Ripard  wrote:
> >
> > Hi Dave,
> >
> > Happy new year :)
>
> And to you.
>
> > On Tue, Jan 02, 2024 at 03:12:26PM +, Dave Stevenson wrote:
> > > Hi Maxime
> > >
> > > On Mon, 14 Nov 2022 at 13:00, Maxime Ripard  wrote:
> > > >
> > > > The current construction of the named mode parsing doesn't allow to 
> > > > extend
> > > > it easily. Let's move it to a separate function so we can add more
> > > > parameters and modes.
> > > >
> > > > In order for the tests to still pass, some extra checks are needed, so
> > > > it's not a 1:1 move.
> > > >
> > > > Reviewed-by: Noralf Trønnes 
> > > > Tested-by: Mateusz Kwiatkowski 
> > > > Signed-off-by: Maxime Ripard 
> > > >
> > > > ---
> > > > Changes in v7:
> > > > - Add Noralf Reviewed-by
> > > >
> > > > Changes in v6:
> > > > - Simplify the test for connection status extras
> > > > - Simplify the code path to call drm_mode_parse_cmdline_named_mode
> > > >
> > > > Changes in v4:
> > > > - Fold down all the named mode patches that were split into a single
> > > >   patch again to maintain bisectability
> > > > ---
> > > >  drivers/gpu/drm/drm_modes.c | 70 
> > > > +
> > > >  1 file changed, 58 insertions(+), 12 deletions(-)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> > > > index 71c050c3ee6b..37542612912b 100644
> > > > --- a/drivers/gpu/drm/drm_modes.c
> > > > +++ b/drivers/gpu/drm/drm_modes.c
> > > > @@ -2229,6 +2229,51 @@ static const char * const 
> > > > drm_named_modes_whitelist[] = {
> > > > "PAL",
> > > >  };
> > > >
> > > > +static int drm_mode_parse_cmdline_named_mode(const char *name,
> > > > +unsigned int name_end,
> > > > +struct drm_cmdline_mode 
> > > > *cmdline_mode)
> > > > +{
> > > > +   unsigned int i;
> > > > +
> > > > +   if (!name_end)
> > > > +   return 0;
> > > > +
> > > > +   /* If the name starts with a digit, it's not a named mode */
> > > > +   if (isdigit(name[0]))
> > > > +   return 0;
> > > > +
> > > > +   /*
> > > > +* If there's an equal sign in the name, the command-line
> > > > +* contains only an option and no mode.
> > > > +*/
> > > > +   if (strnchr(name, name_end, '='))
> > > > +   return 0;
> > > > +
> > > > +   /* The connection status extras can be set without a mode. */
> > > > +   if (name_end == 1 &&
> > > > +   (name[0] == 'd' || name[0] == 'D' || name[0] == 'e'))
> > > > +   return 0;
> > > > +
> > > > +   /*
> > > > +* We're sure we're a named mode at this point, iterate over the
> > > > +* list of modes we're aware of.
> > > > +*/
> > > > +   for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> > > > +   int ret;
> > > > +
> > > > +   ret = str_has_prefix(name, 
> > > > drm_named_modes_whitelist[i]);
> > > > +   if (ret != name_end)
> > > > +   continue;
> > > > +
> > > > +   strcpy(cmdline_mode->name, 
> > > > drm_named_modes_whitelist[i]);
> > > > +   cmdline_mode->specified = true;
> > > > +
> > > > +   return 1;
> > > > +   }
> > > > +
> > > > +   return -EINVAL;
> > > > +}
> > > > +
> > > >  /**
> > > >   * drm_mode_parse_command_line_for_connector - parse command line 
> > > > modeline for connector
> > > >   * @mode_option: optional per connector mode option
> > > > @@ -2265,7 +2310,7 @@ bool 
> > > > drm_mode_parse_command_line_for_connector(const char *mode_option,
> > >

Re: [PATCH v9 09/25] drm/modes: Move named modes parsing to a separate function

2024-01-03 Thread Dave Stevenson
Hi Maxime

On Wed, 3 Jan 2024 at 13:33, Maxime Ripard  wrote:
>
> Hi Dave,
>
> Happy new year :)

And to you.

> On Tue, Jan 02, 2024 at 03:12:26PM +, Dave Stevenson wrote:
> > Hi Maxime
> >
> > On Mon, 14 Nov 2022 at 13:00, Maxime Ripard  wrote:
> > >
> > > The current construction of the named mode parsing doesn't allow to extend
> > > it easily. Let's move it to a separate function so we can add more
> > > parameters and modes.
> > >
> > > In order for the tests to still pass, some extra checks are needed, so
> > > it's not a 1:1 move.
> > >
> > > Reviewed-by: Noralf Trønnes 
> > > Tested-by: Mateusz Kwiatkowski 
> > > Signed-off-by: Maxime Ripard 
> > >
> > > ---
> > > Changes in v7:
> > > - Add Noralf Reviewed-by
> > >
> > > Changes in v6:
> > > - Simplify the test for connection status extras
> > > - Simplify the code path to call drm_mode_parse_cmdline_named_mode
> > >
> > > Changes in v4:
> > > - Fold down all the named mode patches that were split into a single
> > >   patch again to maintain bisectability
> > > ---
> > >  drivers/gpu/drm/drm_modes.c | 70 
> > > +
> > >  1 file changed, 58 insertions(+), 12 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> > > index 71c050c3ee6b..37542612912b 100644
> > > --- a/drivers/gpu/drm/drm_modes.c
> > > +++ b/drivers/gpu/drm/drm_modes.c
> > > @@ -2229,6 +2229,51 @@ static const char * const 
> > > drm_named_modes_whitelist[] = {
> > > "PAL",
> > >  };
> > >
> > > +static int drm_mode_parse_cmdline_named_mode(const char *name,
> > > +unsigned int name_end,
> > > +struct drm_cmdline_mode 
> > > *cmdline_mode)
> > > +{
> > > +   unsigned int i;
> > > +
> > > +   if (!name_end)
> > > +   return 0;
> > > +
> > > +   /* If the name starts with a digit, it's not a named mode */
> > > +   if (isdigit(name[0]))
> > > +   return 0;
> > > +
> > > +   /*
> > > +* If there's an equal sign in the name, the command-line
> > > +* contains only an option and no mode.
> > > +*/
> > > +   if (strnchr(name, name_end, '='))
> > > +   return 0;
> > > +
> > > +   /* The connection status extras can be set without a mode. */
> > > +   if (name_end == 1 &&
> > > +   (name[0] == 'd' || name[0] == 'D' || name[0] == 'e'))
> > > +   return 0;
> > > +
> > > +   /*
> > > +* We're sure we're a named mode at this point, iterate over the
> > > +* list of modes we're aware of.
> > > +*/
> > > +   for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> > > +   int ret;
> > > +
> > > +   ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
> > > +   if (ret != name_end)
> > > +   continue;
> > > +
> > > +   strcpy(cmdline_mode->name, drm_named_modes_whitelist[i]);
> > > +   cmdline_mode->specified = true;
> > > +
> > > +   return 1;
> > > +   }
> > > +
> > > +   return -EINVAL;
> > > +}
> > > +
> > >  /**
> > >   * drm_mode_parse_command_line_for_connector - parse command line 
> > > modeline for connector
> > >   * @mode_option: optional per connector mode option
> > > @@ -2265,7 +2310,7 @@ bool 
> > > drm_mode_parse_command_line_for_connector(const char *mode_option,
> > > const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = 
> > > NULL;
> > > const char *options_ptr = NULL;
> > > char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
> > > -   int i, len, ret;
> > > +   int len, ret;
> > >
> > > memset(mode, 0, sizeof(*mode));
> > > mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
> > > @@ -2306,18 +2351,19 @@ bool 
> > > drm_mode_parse_command_line_for_connector(const char *mode_option,
> > > parse_extras = tr

Re: [PATCH v9 09/25] drm/modes: Move named modes parsing to a separate function

2024-01-02 Thread Dave Stevenson
Hi Maxime

On Mon, 14 Nov 2022 at 13:00, Maxime Ripard  wrote:
>
> The current construction of the named mode parsing doesn't allow to extend
> it easily. Let's move it to a separate function so we can add more
> parameters and modes.
>
> In order for the tests to still pass, some extra checks are needed, so
> it's not a 1:1 move.
>
> Reviewed-by: Noralf Trønnes 
> Tested-by: Mateusz Kwiatkowski 
> Signed-off-by: Maxime Ripard 
>
> ---
> Changes in v7:
> - Add Noralf Reviewed-by
>
> Changes in v6:
> - Simplify the test for connection status extras
> - Simplify the code path to call drm_mode_parse_cmdline_named_mode
>
> Changes in v4:
> - Fold down all the named mode patches that were split into a single
>   patch again to maintain bisectability
> ---
>  drivers/gpu/drm/drm_modes.c | 70 
> +
>  1 file changed, 58 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
> index 71c050c3ee6b..37542612912b 100644
> --- a/drivers/gpu/drm/drm_modes.c
> +++ b/drivers/gpu/drm/drm_modes.c
> @@ -2229,6 +2229,51 @@ static const char * const drm_named_modes_whitelist[] 
> = {
> "PAL",
>  };
>
> +static int drm_mode_parse_cmdline_named_mode(const char *name,
> +unsigned int name_end,
> +struct drm_cmdline_mode 
> *cmdline_mode)
> +{
> +   unsigned int i;
> +
> +   if (!name_end)
> +   return 0;
> +
> +   /* If the name starts with a digit, it's not a named mode */
> +   if (isdigit(name[0]))
> +   return 0;
> +
> +   /*
> +* If there's an equal sign in the name, the command-line
> +* contains only an option and no mode.
> +*/
> +   if (strnchr(name, name_end, '='))
> +   return 0;
> +
> +   /* The connection status extras can be set without a mode. */
> +   if (name_end == 1 &&
> +   (name[0] == 'd' || name[0] == 'D' || name[0] == 'e'))
> +   return 0;
> +
> +   /*
> +* We're sure we're a named mode at this point, iterate over the
> +* list of modes we're aware of.
> +*/
> +   for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> +   int ret;
> +
> +   ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
> +   if (ret != name_end)
> +   continue;
> +
> +   strcpy(cmdline_mode->name, drm_named_modes_whitelist[i]);
> +   cmdline_mode->specified = true;
> +
> +   return 1;
> +   }
> +
> +   return -EINVAL;
> +}
> +
>  /**
>   * drm_mode_parse_command_line_for_connector - parse command line modeline 
> for connector
>   * @mode_option: optional per connector mode option
> @@ -2265,7 +2310,7 @@ bool drm_mode_parse_command_line_for_connector(const 
> char *mode_option,
> const char *bpp_ptr = NULL, *refresh_ptr = NULL, *extra_ptr = NULL;
> const char *options_ptr = NULL;
> char *bpp_end_ptr = NULL, *refresh_end_ptr = NULL;
> -   int i, len, ret;
> +   int len, ret;
>
> memset(mode, 0, sizeof(*mode));
> mode->panel_orientation = DRM_MODE_PANEL_ORIENTATION_UNKNOWN;
> @@ -2306,18 +2351,19 @@ bool drm_mode_parse_command_line_for_connector(const 
> char *mode_option,
> parse_extras = true;
> }
>
> -   /* First check for a named mode */
> -   for (i = 0; i < ARRAY_SIZE(drm_named_modes_whitelist); i++) {
> -   ret = str_has_prefix(name, drm_named_modes_whitelist[i]);
> -   if (ret == mode_end) {
> -   if (refresh_ptr)
> -   return false; /* named + refresh is invalid */
> +   if (!mode_end)
> +   return false;

I'm chasing down a change in behaviour between 6.1 and 6.6, and this
patch seems to be at least part of the cause.

Since [1] we've had the emulated framebuffer on Pi being 16bpp to save
memory. All good.

It used to be possible to use "video=HDMI-A-1:-32" on the kernel
command line to set it back to 32bpp.

After this patch that is no longer possible. "mode_end = bpp_off", and
"bpp_off = bpp_ptr - name", so with bpp_ptr = name we get mode_end
being 0. That fails this conditional.
drm_mode_parse_cmdline_named_mode already aborts early but with no
error if name_end / mode_end is 0, so this "if" clause seems
redundant, and is a change in behaviour.

We do then get a second parsing failure due to the check if (bpp_ptr
|| refresh_ptr) at [2].
Prior to this patch my video= line would get mode->specified set via
"if (ret == mode_end)" removed above, as ret = mode_end = 0. We
therefore didn't evaluate the conditional that now fails.

So I guess my question is whether my command line is valid or not, and
therefore is this a regression?
If considered invalid, then presumably there is no way to update the
bpp without also having 

Re: RPI4B: what is needed for /dev/video10 to work ( v4l_m2m )

2024-01-02 Thread Dave Stevenson
On Tue, 2 Jan 2024 at 10:03, Maxime Ripard  wrote:
>
> Hi,
>
> On Wed, Dec 27, 2023 at 04:19:19PM +0100, AL13N wrote:
> > I have a RPI4B with upstream kernel 6.1 64bit and there is no /dev/video10
> > present. I thought if I waited a bit more, it would appear in the kernel,
> > but that was folly on my part.
> >
> > Currently, watching a movie is painful since the software decoding is way
> > too slow and it has very low fps on 1080p (or even 720p or even 480p)
> >
> > IIRC, someone told me something else has to be fixed before the codecs can
> > be done, but I don't remember what it was, or i didn't find it in my
> > email/the archives.
> >
> > Can someone tell me what exactly needs to be done (in kernel) so that I can
> > take a crack at it, (hopefully with some help)?
> >
> > I don't remember if this was relevant, but there was some talk of needing to
> > use opengl output with a specific texture format for it to work? or is that
> > seperate?
>
> That's something for linux-media. The hardware codec isn't part of vc4
> or v3d, it's a separate controller that requires a separate driver (in
> v4l2).
>
> That driver isn't upstream, and that would need the first thing to
> tackle.

IdeasOnBoard are working on our behalf to clean up the VCHIQ driver in
staging (hopefully unstaging it), and adding the mmal-vchiq, vcsm, and
ISP drivers. 
https://patchwork.linuxtv.org/project/linux-media/list/?series=11633
is probably the latest revision of the series, but there are a number
of supporting series around too.

The codec driver relies on the same mmal-vchiq and vcsm drivers as the
ISP, so adding that afterwards should be relatively simple.

Even though he's stepped back from being a maintainer, Stefan Wahren
is still keeping track of a number of the upstreaming tasks for the Pi
platform - see https://github.com/lategoodbye/rpi-zero/issues/43

  Dave


Re: [PATCH v5 15/44] drm/connector: hdmi: Compute bpc and format automatically

2023-12-14 Thread Dave Stevenson
Hi Maxime

On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> Now that we have all the infrastructure needed, we can add some code
> that will, for a given connector state and mode, compute the best output
> format and bpc.
>
> The algorithm is the same one than the one already found in i915 and
> vc4.

We seem to have some extra words in this sentence.
"The algorithm is the same as that already found in i915 and vc4."?
Possibly "equivalent to" instead of "the same as", as i915 is slightly
different.

> Signed-off-by: Maxime Ripard 
> ---
>  drivers/gpu/drm/drm_atomic_state_helper.c  | 183 ++-
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 529 
> -
>  drivers/gpu/drm/tests/drm_kunit_edid.h | 160 +++
>  3 files changed, 860 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index a36edda590f8..2442b5a2d94f 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -682,6 +682,96 @@ static bool hdmi_is_full_range(const struct 
> drm_connector *connector,
> return drm_default_rgb_quant_range(mode) == 
> HDMI_QUANTIZATION_RANGE_FULL ? true : false;
>  }
>
> +static bool
> +sink_supports_format_bpc(const struct drm_connector *connector,
> +const struct drm_display_info *info,
> +const struct drm_display_mode *mode,
> +unsigned int format, unsigned int bpc)
> +{
> +   struct drm_device *dev = connector->dev;
> +   u8 vic = drm_match_cea_mode(mode);
> +
> +   if (vic == 1 && bpc != 8) {
> +   drm_dbg(dev, "VIC1 requires a bpc of 8, got %u\n", bpc);
> +   return false;
> +   }
> +
> +   if (!info->is_hdmi &&
> +   (format != HDMI_COLORSPACE_RGB || bpc != 8)) {
> +   drm_dbg(dev, "DVI Monitors require an RGB output at 8 bpc\n");
> +   return false;
> +   }
> +
> +   if (!(connector->hdmi.supported_formats & BIT(format))) {
> +   drm_dbg(dev, "%s format unsupported by the connector.\n",
> +   drm_hdmi_connector_get_output_format_name(format));
> +   return false;
> +   }
> +
> +   switch (format) {
> +   case HDMI_COLORSPACE_RGB:
> +   drm_dbg(dev, "RGB Format, checking the constraints.\n");
> +
> +   if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444))
> +   return false;

We've dropped this check from vc4 in our downstream kernel as it stops
you using the prebaked EDIDs (eg drm.edid_firmware=edid/1024x768.bin),
or any other EDID that is defined as an analog monitor.
The EDID parsing bombs out at [1], so info->color_formats gets left at 0.

RGB is mandatory for both DVI and HDMI, so rejecting it seems overly fussy.

I don't see i915 making use of info->color_formats at all. The
equivalent function looks to be intel_hdmi_sink_bpc_possible [2] which
just accepts anything for 8bpc output.

  Dave

PS I'll have to defer looking at patch 16 for another day - it just
needs a bit more analysis than I can fit in today.

[1] 
https://elixir.free-electrons.com/linux/latest/source/drivers/gpu/drm/drm_edid.c#L6533
[2] 
https://elixir.bootlin.com/linux/latest/source/drivers/gpu/drm/i915/display/intel_hdmi.c#L1909

> +
> +   if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & 
> DRM_EDID_HDMI_DC_30)) {
> +   drm_dbg(dev, "10 BPC but sink doesn't support Deep 
> Color 30.\n");
> +   return false;
> +   }
> +
> +   if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & 
> DRM_EDID_HDMI_DC_36)) {
> +   drm_dbg(dev, "12 BPC but sink doesn't support Deep 
> Color 36.\n");
> +   return false;
> +   }
> +
> +   drm_dbg(dev, "RGB format supported in that configuration.\n");
> +
> +   return true;
> +
> +   case HDMI_COLORSPACE_YUV422:
> +   drm_dbg(dev, "YUV422 format, checking the constraints.\n");
> +
> +   if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) {
> +   drm_dbg(dev, "Sink doesn't support YUV422.\n");
> +   return false;
> +   }
> +
> +   if (bpc != 12) {
> +   drm_dbg(dev, "YUV422 only supports 12 bpc.\n");
> +   return false;
> +   }
> +
> +   drm_dbg(dev, "YUV422 format supported in that 
> configuration.\n");
> +
> +   return true;
> +
> +   case HDMI_COLORSPACE_YUV444:
> +   drm_dbg(dev, "YUV444 format, checking the constraints.\n");
> +
> +   if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) {
> +   drm_dbg(dev, "Sink doesn't support YUV444.\n");
> +   return false;
> 

Re: [PATCH v5 14/44] drm/connector: hdmi: Add custom hook to filter TMDS character rate

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> Most of the HDMI controllers have an upper TMDS character rate limit
> they can't exceed. On "embedded"-grade display controllers, it will
> typically be lower than what high-grade monitors can provide these days,
> so drivers will filter the TMDS character rate based on the controller
> capabilities.
>
> To make that easier to handle for drivers, let's provide an optional
> hook to be implemented by drivers so they can tell the HDMI controller
> helpers if a given TMDS character rate is reachable for them or not.
>
> This will then be useful to figure out the best format and bpc count for
> a given mode.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic_state_helper.c  |  9 +++
>  drivers/gpu/drm/drm_connector.c|  4 ++
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 69 
> ++
>  drivers/gpu/drm/tests/drm_connector_test.c | 15 +
>  include/drm/drm_connector.h| 30 ++
>  5 files changed, 127 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 74bc3cc53c2d..a36edda590f8 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -687,11 +687,20 @@ hdmi_clock_valid(const struct drm_connector *connector,
>  const struct drm_display_mode *mode,
>  unsigned long long clock)
>  {
> +   const struct drm_connector_hdmi_funcs *funcs = connector->hdmi.funcs;
> const struct drm_display_info *info = >display_info;
>
> if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
> return MODE_CLOCK_HIGH;
>
> +   if (funcs && funcs->tmds_char_rate_valid) {
> +   enum drm_mode_status status;
> +
> +   status = funcs->tmds_char_rate_valid(connector, mode, clock);
> +   if (status != MODE_OK)
> +   return status;
> +   }
> +
> return MODE_OK;
>  }
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 667326b09acc..9f314fee26ce 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -457,6 +457,7 @@ EXPORT_SYMBOL(drmm_connector_init);
>   * @dev: DRM device
>   * @connector: A pointer to the HDMI connector to init
>   * @funcs: callbacks for this connector
> + * @hdmi_funcs: HDMI-related callbacks for this connector
>   * @connector_type: user visible type of the connector
>   * @ddc: optional pointer to the associated ddc adapter
>   * @supported_formats: Bitmask of @hdmi_colorspace listing supported output 
> formats
> @@ -476,6 +477,7 @@ EXPORT_SYMBOL(drmm_connector_init);
>  int drmm_connector_hdmi_init(struct drm_device *dev,
>  struct drm_connector *connector,
>  const struct drm_connector_funcs *funcs,
> +const struct drm_connector_hdmi_funcs 
> *hdmi_funcs,
>  int connector_type,
>  struct i2c_adapter *ddc,
>  unsigned long supported_formats,
> @@ -512,6 +514,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
> if (max_bpc > 8)
> drm_connector_attach_hdr_output_metadata_property(connector);
>
> +   connector->hdmi.funcs = hdmi_funcs;
> +
> return 0;
>  }
>  EXPORT_SYMBOL(drmm_connector_hdmi_init);
> diff --git a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c 
> b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> index d76fafb91025..e7dbdd4a4e7f 100644
> --- a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> +++ b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> @@ -110,6 +110,21 @@ static int set_connector_edid(struct kunit *test, struct 
> drm_connector *connecto
> return 0;
>  }
>
> +static const struct drm_connector_hdmi_funcs dummy_connector_hdmi_funcs = {
> +};
> +
> +static enum drm_mode_status
> +reject_connector_tmds_char_rate_valid(const struct drm_connector *connector,
> +  const struct drm_display_mode *mode,
> +  unsigned long long tmds_rate)
> +{
> +   return MODE_BAD;
> +}
> +
> +static const struct drm_connector_hdmi_funcs reject_connector_hdmi_funcs = {
> +   .tmds_char_rate_valid   = reject_connector_tmds_char_rate_valid,
>

Re: [PATCH v5 13/44] drm/connector: hdmi: Calculate TMDS character rate

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> Most HDMI drivers have some code to calculate the TMDS character rate,
> usually to adjust an internal clock to match what the mode requires.
>
> Since the TMDS character rates mostly depends on the resolution, whether
> we need to repeat pixels or not, the bpc count and the format, we can
> now derive it from the HDMI connector state that stores all those infos
> and remove the duplication from drivers.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic.c   |   1 +
>  drivers/gpu/drm/drm_atomic_state_helper.c  |  44 +
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 169 
>  drivers/gpu/drm/tests/drm_kunit_edid.h | 216 
> +
>  include/drm/drm_connector.h|   5 +
>  5 files changed, 435 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 7aaa2a4d70d9..4f6493f91eed 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1150,6 +1150,7 @@ static void drm_atomic_connector_print_state(struct 
> drm_printer *p,
> drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
> drm_printf(p, "\toutput_format=%s\n",
>
> drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
> +   drm_printf(p, "\ttmds_char_rate=%llu\n", 
> state->hdmi.tmds_char_rate);
> }
>
> if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 92e1b087c3d0..74bc3cc53c2d 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -682,6 +682,41 @@ static bool hdmi_is_full_range(const struct 
> drm_connector *connector,
> return drm_default_rgb_quant_range(mode) == 
> HDMI_QUANTIZATION_RANGE_FULL ? true : false;
>  }
>
> +static enum drm_mode_status
> +hdmi_clock_valid(const struct drm_connector *connector,
> +const struct drm_display_mode *mode,
> +unsigned long long clock)
> +{
> +   const struct drm_display_info *info = >display_info;
> +
> +   if (info->max_tmds_clock && clock > info->max_tmds_clock * 1000)
> +   return MODE_CLOCK_HIGH;
> +
> +   return MODE_OK;
> +}
> +
> +static int
> +hdmi_compute_clock(const struct drm_connector *connector,
> +  struct drm_connector_state *state,
> +  const struct drm_display_mode *mode,
> +  unsigned int bpc, enum hdmi_colorspace fmt)
> +{
> +   enum drm_mode_status status;
> +   unsigned long long clock;
> +
> +   clock = drm_connector_hdmi_compute_mode_clock(mode, bpc, fmt);
> +   if (!clock)
> +   return -EINVAL;
> +
> +   status = hdmi_clock_valid(connector, mode, clock);
> +   if (status != MODE_OK)
> +   return -EINVAL;
> +
> +   state->hdmi.tmds_char_rate = clock;
> +
> +   return 0;
> +}
> +
>  /**
>   * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
> atomic state
>   * @connector: DRM Connector
> @@ -701,9 +736,18 @@ int drm_atomic_helper_connector_hdmi_check(struct 
> drm_connector *connector,
> drm_atomic_get_old_connector_state(state, connector);
> struct drm_connector_state *new_state =
> drm_atomic_get_new_connector_state(state, connector);
> +   const struct drm_display_mode *mode =
> +   connector_state_get_mode(new_state);
> +   int ret;
>
> new_state->hdmi.is_full_range = hdmi_is_full_range(connector, 
> new_state);
>
> +   ret = hdmi_compute_clock(connector, new_state, mode,
> +new_state->hdmi.output_bpc,
> +new_state->hdmi.output_format);
> +   if (ret)
> +   return ret;
> +
> if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb ||
> old_state->hdmi.output_bpc != new_state->hdmi.output_bpc ||
> old_state->hdmi.output_format != new_state->hdmi.output_format) {
> diff --git a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c 
> b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> index 4e2ec436987b..d76fafb91025 100644
> --- a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> +++ b/drivers/gpu/drm/tests/drm_at

Re: [PATCH v5 12/44] drm/connector: hdmi: Add HDMI compute clock helper

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> A lot of HDMI drivers have some variation of the formula to calculate
> the TMDS character rate from a mode, but few of them actually take all
> parameters into account.
>
> Let's create a helper to provide that rate taking all parameters into
> account.
>
> Signed-off-by: Maxime Ripard 
> ---
>  drivers/gpu/drm/drm_connector.c|  59 ++
>  drivers/gpu/drm/tests/drm_connector_test.c | 323 
> +
>  include/drm/drm_connector.h|   5 +
>  3 files changed, 387 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index a72f38b6dbc8..667326b09acc 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -2973,6 +2973,65 @@ void drm_connector_update_privacy_screen(const struct 
> drm_connector_state *conne
>  }
>  EXPORT_SYMBOL(drm_connector_update_privacy_screen);
>
> +/**
> + * drm_connector_hdmi_compute_mode_clock() - Computes the TMDS Character Rate
> + * @mode: Display mode to compute the clock for
> + * @bpc: Bits per character
> + * @fmt: Output Pixel Format used
> + *
> + * Returns the TMDS Character Rate for a given mode, bpc count and output 
> format.
> + *
> + * RETURNS:
> + * The TMDS Character Rate, in Hertz, or 0 on error.
> + */
> +unsigned long long
> +drm_connector_hdmi_compute_mode_clock(const struct drm_display_mode *mode,
> + unsigned int bpc,
> + enum hdmi_colorspace fmt)
> +{
> +   unsigned long long clock = mode->clock * 1000ULL;
> +   unsigned int vic = drm_match_cea_mode(mode);
> +
> +   /*
> +* CTA-861-G Spec, section 5.4 - Color Coding and Quantization
> +* mandates that VIC 1 always uses 8 bpc.
> +*/
> +   if (vic == 1 && bpc != 8)
> +   return 0;
> +
> +   /*
> +* HDMI 2.0 Spec, section 7.1 - YCbCr 4:2:0 Pixel Encoding
> +* specifies that YUV420 encoding is only available for those
> +* VICs.
> +*/
> +   if (fmt == HDMI_COLORSPACE_YUV420 &&
> +   !(vic == 96 || vic == 97 || vic == 101 ||
> + vic == 102 || vic == 106 || vic == 107))
> +   return 0;
> +
> +   /*
> +* HDMI 1.4b Spec, section 6.2.3 - Pixel Encoding Requirements
> +* specifies that YUV422 is 36-bit only.
> +*/
> +   if (fmt == HDMI_COLORSPACE_YUV422 && bpc != 12)
> +   return 0;
> +
> +   if (fmt == HDMI_COLORSPACE_YUV420)
> +   clock = clock / 2;
> +
> +   if (mode->flags & DRM_MODE_FLAG_DBLCLK)
> +   clock = clock * 2;
> +
> +   if (fmt == HDMI_COLORSPACE_YUV422)
> +   bpc = 8;

Possibly a comment on why we have these munges for 420 and 422 as they
aren't immediately obvious.

Reviewed-by: Dave Stevenson 

> +
> +   clock = clock * bpc;
> +   do_div(clock, 8);
> +
> +   return clock;
> +}
> +EXPORT_SYMBOL(drm_connector_hdmi_compute_mode_clock);
> +
>  int drm_connector_set_obj_prop(struct drm_mode_object *obj,
> struct drm_property *property,
> uint64_t value)
> diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
> b/drivers/gpu/drm/tests/drm_connector_test.c
> index fa6fe8084107..0a838924a546 100644
> --- a/drivers/gpu/drm/tests/drm_connector_test.c
> +++ b/drivers/gpu/drm/tests/drm_connector_test.c
> @@ -8,7 +8,9 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
> +#include 
>
>  #include 
>
> @@ -719,10 +721,331 @@ static struct kunit_suite 
> drm_connector_attach_broadcast_rgb_property_test_suite
> .test_cases = drm_connector_attach_broadcast_rgb_property_tests,
>  };
>
> +/*
> + * Test that for a given mode, with 8bpc and an RGB output the TMDS
> + * character rate is equal to the mode pixel clock.
> + */
> +static void drm_test_drm_connector_hdmi_compute_mode_clock_rgb(struct kunit 
> *test)
> +{
> +   struct drm_connector_init_priv *priv = test->priv;
> +   const struct drm_display_mode *mode;
> +   unsigned long long rate;
> +   struct drm_device *drm = >drm;
> +
> +   mode = drm_display_mode_from_cea_vic(drm, 16);
> +   KUNIT_ASSERT_NOT_NULL(test, mode);
> +
> +   KUNIT_ASSERT_FALSE(test, mode->flags & DRM_MODE_FLAG_DBLCLK);
> +
> +   rate = drm_connector_hdmi_compute_mode_clock(mode, 8, 
> HDMI_COLORSPACE_RGB);
> +   KUNIT_ASSERT_GT(test, rate, 0);
> +   KUNI

Re: [PATCH v5 11/44] drm/connector: hdmi: Add support for output format

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> Just like BPC, we'll add support for automatic selection of the output
> format for HDMI connectors.
>
> Let's add the needed defaults and fields for now.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic.c   |   2 +
>  drivers/gpu/drm/drm_atomic_state_helper.c  |   3 +-
>  drivers/gpu/drm/drm_connector.c|  31 ++
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   |  90 ++---
>  drivers/gpu/drm/tests/drm_connector_test.c | 109 
> -
>  include/drm/drm_connector.h|  19 
>  6 files changed, 238 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 76c63ed04af4..7aaa2a4d70d9 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1148,6 +1148,8 @@ static void drm_atomic_connector_print_state(struct 
> drm_printer *p,
>
> drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
> drm_printf(p, "\tis_full_range=%c\n", 
> state->hdmi.is_full_range ? 'y' : 'n');
> drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
> +   drm_printf(p, "\toutput_format=%s\n",
> +  
> drm_hdmi_connector_get_output_format_name(state->hdmi.output_format));
> }
>
> if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 883bdc0349c0..92e1b087c3d0 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -705,7 +705,8 @@ int drm_atomic_helper_connector_hdmi_check(struct 
> drm_connector *connector,
> new_state->hdmi.is_full_range = hdmi_is_full_range(connector, 
> new_state);
>
> if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb ||
> -   old_state->hdmi.output_bpc != new_state->hdmi.output_bpc) {
> +   old_state->hdmi.output_bpc != new_state->hdmi.output_bpc ||
> +   old_state->hdmi.output_format != new_state->hdmi.output_format) {
> struct drm_crtc *crtc = new_state->crtc;
> struct drm_crtc_state *crtc_state;
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 139ac3d8160c..a72f38b6dbc8 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -459,6 +459,7 @@ EXPORT_SYMBOL(drmm_connector_init);
>   * @funcs: callbacks for this connector
>   * @connector_type: user visible type of the connector
>   * @ddc: optional pointer to the associated ddc adapter
> + * @supported_formats: Bitmask of @hdmi_colorspace listing supported output 
> formats
>   * @max_bpc: Maximum bits per char the HDMI connector supports
>   *
>   * Initialises a preallocated HDMI connector. Connectors can be
> @@ -477,6 +478,7 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>  const struct drm_connector_funcs *funcs,
>  int connector_type,
>  struct i2c_adapter *ddc,
> +unsigned long supported_formats,
>  unsigned int max_bpc)
>  {
> int ret;
> @@ -485,6 +487,9 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>   connector_type == DRM_MODE_CONNECTOR_HDMIB))
> return -EINVAL;
>
> +   if (!supported_formats || !(supported_formats & 
> BIT(HDMI_COLORSPACE_RGB)))
> +   return -EINVAL;
> +
> if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
> return -EINVAL;
>
> @@ -492,6 +497,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
> if (ret)
> return ret;
>
> +   connector->hdmi.supported_formats = supported_formats;
> +
> /*
>  * drm_connector_attach_max_bpc_property() requires the
>  * connector to have a state.
> @@ -1224,6 +1231,30 @@ drm_hdmi_connector_get_broadcast_rgb_name(enum 
> drm_hdmi_broadcast_rgb broadcast_
>  }
>  EXPORT_SYMBOL(drm_hdmi_connector_get_broadcast_rgb_name);
>
> +static const char * const output_format_str[] = {
> +   [HDMI_COLORSPACE_RGB]   = "RGB",
> +   [HDMI_COLORSPACE_YUV420]= "YUV 4:2:0",
> +   [HDMI_COLORSPACE_YUV422]= "YUV 4:2:

Re: [PATCH v5 10/44] drm/connector: hdmi: Add output BPC to the connector state

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> We'll add automatic selection of the output BPC in a following patch,
> but let's add it to the HDMI connector state already.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic.c   |   1 +
>  drivers/gpu/drm/drm_atomic_state_helper.c  |   7 +-
>  drivers/gpu/drm/drm_connector.c|  20 +-
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 227 
> -
>  drivers/gpu/drm/tests/drm_connector_test.c | 153 +-
>  include/drm/drm_connector.h|  13 +-
>  6 files changed, 402 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index e4ad53e64e07..76c63ed04af4 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1147,6 +1147,7 @@ static void drm_atomic_connector_print_state(struct 
> drm_printer *p,
> drm_printf(p, "\tbroadcast_rgb=%s\n",
>
> drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
> drm_printf(p, "\tis_full_range=%c\n", 
> state->hdmi.is_full_range ? 'y' : 'n');
> +   drm_printf(p, "\toutput_bpc=%u\n", state->hdmi.output_bpc);
> }
>
> if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 4a7114978c47..883bdc0349c0 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -584,6 +584,10 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
>  void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector 
> *connector,
>   struct drm_connector_state 
> *new_state)
>  {
> +   unsigned int max_bpc = connector->max_bpc;
> +
> +   new_state->max_bpc = max_bpc;
> +   new_state->max_requested_bpc = max_bpc;
> new_state->hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_AUTO;
>  }
>  EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
> @@ -700,7 +704,8 @@ int drm_atomic_helper_connector_hdmi_check(struct 
> drm_connector *connector,
>
> new_state->hdmi.is_full_range = hdmi_is_full_range(connector, 
> new_state);
>
> -   if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb) {
> +   if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb ||
> +   old_state->hdmi.output_bpc != new_state->hdmi.output_bpc) {
> struct drm_crtc *crtc = new_state->crtc;
> struct drm_crtc_state *crtc_state;
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 929b0a911f62..139ac3d8160c 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -459,6 +459,7 @@ EXPORT_SYMBOL(drmm_connector_init);
>   * @funcs: callbacks for this connector
>   * @connector_type: user visible type of the connector
>   * @ddc: optional pointer to the associated ddc adapter
> + * @max_bpc: Maximum bits per char the HDMI connector supports
>   *
>   * Initialises a preallocated HDMI connector. Connectors can be
>   * subclassed as part of driver connector objects.
> @@ -475,7 +476,8 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>  struct drm_connector *connector,
>  const struct drm_connector_funcs *funcs,
>  int connector_type,
> -struct i2c_adapter *ddc)
> +struct i2c_adapter *ddc,
> +unsigned int max_bpc)
>  {
> int ret;
>
> @@ -483,10 +485,26 @@ int drmm_connector_hdmi_init(struct drm_device *dev,
>   connector_type == DRM_MODE_CONNECTOR_HDMIB))
> return -EINVAL;
>
> +   if (!(max_bpc == 8 || max_bpc == 10 || max_bpc == 12))
> +   return -EINVAL;
> +
> ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
> if (ret)
> return ret;
>
> +   /*
> +* drm_connector_attach_max_bpc_property() requires the
> +* connector to have a state.
> +*/
> +   if (connector->funcs->reset)
> +   connector->funcs->reset(connector);
> +
> +   drm_connector_attach_max_bpc_property(connector, 8, max_bpc);
> +   connector->max_bpc = max_bpc;
> +
> +   i

Re: [PATCH v5 09/44] drm/connector: hdmi: Add RGB Quantization Range to the connector state

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> HDMI controller drivers will need to figure out the RGB range they need
> to configure based on a mode and property values. Let's expose that in
> the HDMI connector state so drivers can just use that value.

Again a mention that we're also adding unit tests wouldn't be amiss.

> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic.c   |   4 +-
>  drivers/gpu/drm/drm_atomic_state_helper.c  |  44 +++
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 335 
> +
>  include/drm/drm_atomic_state_helper.h  |   1 +
>  include/drm/drm_connector.h|   6 +
>  5 files changed, 389 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 1465a7f09a0b..e4ad53e64e07 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1143,9 +1143,11 @@ static void drm_atomic_connector_print_state(struct 
> drm_printer *p,
> drm_printf(p, "\tcolorspace=%s\n", 
> drm_get_colorspace_name(state->colorspace));
>
> if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
> -   connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
> +   connector->connector_type == DRM_MODE_CONNECTOR_HDMIB) {
> drm_printf(p, "\tbroadcast_rgb=%s\n",
>
> drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
> +   drm_printf(p, "\tis_full_range=%c\n", 
> state->hdmi.is_full_range ? 'y' : 'n');
> +   }
>
> if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> if (state->writeback_job && state->writeback_job->fb)
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 10d98620a358..4a7114978c47 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -31,6 +31,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -636,6 +637,47 @@ int drm_atomic_helper_connector_tv_check(struct 
> drm_connector *connector,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
>
> +static const struct drm_display_mode *
> +connector_state_get_mode(const struct drm_connector_state *conn_state)
> +{
> +   struct drm_atomic_state *state;
> +   struct drm_crtc_state *crtc_state;
> +   struct drm_crtc *crtc;
> +
> +   state = conn_state->state;
> +   if (!state)
> +   return NULL;
> +
> +   crtc = conn_state->crtc;
> +   if (!crtc)
> +   return NULL;
> +
> +   crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> +   if (!crtc_state)
> +   return NULL;
> +
> +   return _state->mode;
> +}
> +
> +static bool hdmi_is_full_range(const struct drm_connector *connector,
> +  const struct drm_connector_state *state)
> +{
> +   const struct drm_display_info *display = >display_info;
> +   const struct drm_display_mode *mode =
> +   connector_state_get_mode(state);
> +
> +   if (state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_FULL)
> +   return true;
> +
> +   if (state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED)
> +   return false;
> +
> +   if (!display->is_hdmi)
> +   return true;
> +
> +   return drm_default_rgb_quant_range(mode) == 
> HDMI_QUANTIZATION_RANGE_FULL ? true : false;
> +}
> +
>  /**
>   * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
> atomic state
>   * @connector: DRM Connector
> @@ -656,6 +698,8 @@ int drm_atomic_helper_connector_hdmi_check(struct 
> drm_connector *connector,
> struct drm_connector_state *new_state =
> drm_atomic_get_new_connector_state(state, connector);
>
> +   new_state->hdmi.is_full_range = hdmi_is_full_range(connector, 
> new_state);
> +
> if (old_state->hdmi.broadcast_rgb != new_state->hdmi.broadcast_rgb) {
> struct drm_crtc *crtc = new_state->crtc;
> struct drm_crtc_state *crtc_state;
> diff --git a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c 
> b/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> index 21e6f796ee13..7750c3d214a4 100644
> --- a/drivers/gpu/drm/tests/drm_atomic_state_helper_test.c
> +++ b/drivers/gpu/dr

Re: [PATCH v5 08/44] drm/connector: hdmi: Add Broadcast RGB property

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> The i915 driver has a property to force the RGB range of an HDMI output.
> The vc4 driver then implemented the same property with the same
> semantics. KWin has support for it, and a PR for mutter is also there to
> support it.
>
> Both drivers implementing the same property with the same semantics,
> plus the userspace having support for it, is proof enough that it's
> pretty much a de-facto standard now and we can provide helpers for it.
>
> Let's plumb it into the newly created HDMI connector.

To have such a significant proportion of the patch being kunit tests
when there was no reference to such in the commit text was slightly
unexpected.

> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  Documentation/gpu/kms-properties.csv   |   1 -
>  drivers/gpu/drm/drm_atomic.c   |   5 +
>  drivers/gpu/drm/drm_atomic_state_helper.c  |  17 +
>  drivers/gpu/drm/drm_atomic_uapi.c  |   4 +
>  drivers/gpu/drm/drm_connector.c|  76 +
>  drivers/gpu/drm/tests/Makefile |   1 +
>  .../gpu/drm/tests/drm_atomic_state_helper_test.c   | 376 
> +
>  drivers/gpu/drm/tests/drm_connector_test.c | 117 ++-
>  drivers/gpu/drm/tests/drm_kunit_edid.h | 106 ++
>  include/drm/drm_connector.h|  36 ++
>  10 files changed, 737 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/gpu/kms-properties.csv 
> b/Documentation/gpu/kms-properties.csv
> index 0f9590834829..caef14c532d4 100644
> --- a/Documentation/gpu/kms-properties.csv
> +++ b/Documentation/gpu/kms-properties.csv
> @@ -17,7 +17,6 @@ Owner Module/Drivers,Group,Property Name,Type,Property 
> Values,Object attached,De
>  ,Virtual GPU,“suggested X”,RANGE,"Min=0, Max=0x",Connector,property 
> to suggest an X offset for a connector
>  ,,“suggested Y”,RANGE,"Min=0, Max=0x",Connector,property to suggest 
> an Y offset for a connector
>  ,Optional,"""aspect ratio""",ENUM,"{ ""None"", ""4:3"", ""16:9"" 
> }",Connector,TDB
> -i915,Generic,"""Broadcast RGB""",ENUM,"{ ""Automatic"", ""Full"", ""Limited 
> 16:235"" }",Connector,"When this property is set to Limited 16:235 and CTM is 
> set, the hardware will be programmed with the result of the multiplication of 
> CTM by the limited range matrix to ensure the pixels normally in the range 
> 0..1.0 are remapped to the range 16/255..235/255."
>  ,,“audio”,ENUM,"{ ""force-dvi"", ""off"", ""auto"", ""on"" }",Connector,TBD
>  ,SDVO-TV,“mode”,ENUM,"{ ""NTSC_M"", ""NTSC_J"", ""NTSC_443"", ""PAL_B"" } 
> etc.",Connector,TBD
>  ,,"""left_margin""",RANGE,"Min=0, Max= SDVO dependent",Connector,TBD
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index c31fc0b48c31..1465a7f09a0b 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -1142,6 +1142,11 @@ static void drm_atomic_connector_print_state(struct 
> drm_printer *p,
> drm_printf(p, "\tmax_requested_bpc=%d\n", state->max_requested_bpc);
> drm_printf(p, "\tcolorspace=%s\n", 
> drm_get_colorspace_name(state->colorspace));
>
> +   if (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA ||
> +   connector->connector_type == DRM_MODE_CONNECTOR_HDMIB)
> +   drm_printf(p, "\tbroadcast_rgb=%s\n",
> +  
> drm_hdmi_connector_get_broadcast_rgb_name(state->hdmi.broadcast_rgb));
> +
> if (connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
> if (state->writeback_job && state->writeback_job->fb)
> drm_printf(p, "\tfb=%d\n", 
> state->writeback_job->fb->base.id);
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index e69c0cc1c6da..10d98620a358 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -583,6 +583,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
>  void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector 
> *connector,
>   struct dr

Re: [PATCH v5 07/44] drm/connector: hdmi: Create an HDMI sub-state

2023-12-14 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> The next features we will need to share across drivers will need to
> store some parameters for drivers to use, such as the selected output
> format.
>
> Let's create a new connector sub-state dedicated to HDMI controllers,
> that will eventually store everything we need.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_atomic_state_helper.c | 35 
> +++
>  include/drm/drm_atomic_state_helper.h |  4 
>  include/drm/drm_connector.h   |  7 +++
>  3 files changed, 46 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c 
> b/drivers/gpu/drm/drm_atomic_state_helper.c
> index 54975de44a0e..e69c0cc1c6da 100644
> --- a/drivers/gpu/drm/drm_atomic_state_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_state_helper.c
> @@ -570,6 +570,22 @@ void drm_atomic_helper_connector_tv_reset(struct 
> drm_connector *connector)
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_tv_reset);
>
> +/**
> + * __drm_atomic_helper_connector_hdmi_reset() - Initializes all HDMI 
> @drm_connector_state resources
> + * @connector: DRM connector
> + * @new_state: connector state to reset
> + *
> + * Initializes all HDMI resources from a @drm_connector_state without
> + * actually allocating it. This is useful for HDMI drivers, in
> + * combination with __drm_atomic_helper_connector_reset() or
> + * drm_atomic_helper_connector_reset().
> + */
> +void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector 
> *connector,
> + struct drm_connector_state 
> *new_state)
> +{
> +}
> +EXPORT_SYMBOL(__drm_atomic_helper_connector_hdmi_reset);
> +
>  /**
>   * drm_atomic_helper_connector_tv_check - Validate an analog TV connector 
> state
>   * @connector: DRM Connector
> @@ -619,6 +635,25 @@ int drm_atomic_helper_connector_tv_check(struct 
> drm_connector *connector,
>  }
>  EXPORT_SYMBOL(drm_atomic_helper_connector_tv_check);
>
> +/**
> + * drm_atomic_helper_connector_hdmi_check() - Helper to check HDMI connector 
> atomic state
> + * @connector: DRM Connector
> + * @state: the DRM State object
> + *
> + * Provides a default connector state check handler for HDMI connectors.
> + * Checks that a desired connector update is valid, and updates various
> + * fields of derived state.
> + *
> + * RETURNS:
> + * Zero on success, or an errno code otherwise.
> + */
> +int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
> +  struct drm_atomic_state *state)
> +{
> +   return 0;
> +}
> +EXPORT_SYMBOL(drm_atomic_helper_connector_hdmi_check);
> +
>  /**
>   * __drm_atomic_helper_connector_duplicate_state - copy atomic connector 
> state
>   * @connector: connector object
> diff --git a/include/drm/drm_atomic_state_helper.h 
> b/include/drm/drm_atomic_state_helper.h
> index b9740edb2658..d59d2b3aef9a 100644
> --- a/include/drm/drm_atomic_state_helper.h
> +++ b/include/drm/drm_atomic_state_helper.h
> @@ -71,7 +71,11 @@ void __drm_atomic_helper_connector_state_reset(struct 
> drm_connector_state *conn_
>  void __drm_atomic_helper_connector_reset(struct drm_connector *connector,
>  struct drm_connector_state 
> *conn_state);
>  void drm_atomic_helper_connector_reset(struct drm_connector *connector);
> +void __drm_atomic_helper_connector_hdmi_reset(struct drm_connector 
> *connector,
> + struct drm_connector_state 
> *new_state);
>  void drm_atomic_helper_connector_tv_reset(struct drm_connector *connector);
> +int drm_atomic_helper_connector_hdmi_check(struct drm_connector *connector,
> +  struct drm_atomic_state *state);
>  int drm_atomic_helper_connector_tv_check(struct drm_connector *connector,
>  struct drm_atomic_state *state);
>  void drm_atomic_helper_connector_tv_margins_reset(struct drm_connector 
> *connector);
> diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> index 4491c4c2fb6e..000a2a156619 100644
> --- a/include/drm/drm_connector.h
> +++ b/include/drm/drm_connector.h
> @@ -1031,6 +1031,13 @@ struct drm_connector_state {
>  * DRM blob property for HDR output metadata
>  */
> struct drm_property_blob *hdr_output_metadata;
> +
> +   /**
> +* @hdmi: HDMI-related variable and properties. Filled by
> +* @drm_atomic_helper_connector_hdmi_check().
> +*/
> +   struct {
> +   } hdmi;
>  };
>
>  /**
>
> --
> 2.43.0
>


Re: [PATCH v5 06/44] drm/connector: Introduce an HDMI connector initialization function

2023-12-14 Thread Dave Stevenson
Hi Maxime

As requested, I'm just going through patches 6-16.
I will say that I've been less thorough in checking the kunit test
code in this series than the core code changes, and I'm trusting that
all the unit tests pass.

I get a build failure on the complete series for arm64 with the
standard defconfig
depmod: ERROR: Cycle detected: drm_display_helper -> drm_kms_helper ->
drm_display_helper
depmod: ERROR: Cycle detected: drm
depmod: ERROR: Found 2 modules in dependency cycles!

I haven't followed it through as to the reason, but obviously that
will need to be addressed.

  Dave

On Thu, 7 Dec 2023 at 15:49, Maxime Ripard  wrote:
>
> A lot of the various HDMI drivers duplicate some logic that depends on
> the HDMI spec itself and not really a particular hardware
> implementation.
>
> Output BPC or format selection, infoframe generation are good examples
> of such areas.
>
> This creates a lot of boilerplate, with a lot of variations, which makes
> it hard for userspace to rely on, and makes it difficult to get it right
> for drivers.
>
> In the next patches, we'll add a lot of infrastructure around the
> drm_connector and drm_connector_state structures, which will allow to
> abstract away the duplicated logic. This infrastructure comes with a few
> requirements though, and thus we need a new initialization function.
>
> Hopefully, this will make drivers simpler to handle, and their behaviour
> more consistent.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_connector.c|  39 +
>  drivers/gpu/drm/tests/drm_connector_test.c | 123 
> +
>  include/drm/drm_connector.h|   5 ++
>  3 files changed, 167 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index b0516505f7ae..d9961cce8245 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -452,6 +452,45 @@ int drmm_connector_init(struct drm_device *dev,
>  }
>  EXPORT_SYMBOL(drmm_connector_init);
>
> +/**
> + * drmm_connector_hdmi_init - Init a preallocated HDMI connector
> + * @dev: DRM device
> + * @connector: A pointer to the HDMI connector to init
> + * @funcs: callbacks for this connector
> + * @connector_type: user visible type of the connector
> + * @ddc: optional pointer to the associated ddc adapter
> + *
> + * Initialises a preallocated HDMI connector. Connectors can be
> + * subclassed as part of driver connector objects.
> + *
> + * Cleanup is automatically handled with a call to
> + * drm_connector_cleanup() in a DRM-managed action.
> + *
> + * The connector structure should be allocated with drmm_kzalloc().
> + *
> + * Returns:
> + * Zero on success, error code on failure.
> + */
> +int drmm_connector_hdmi_init(struct drm_device *dev,
> +struct drm_connector *connector,
> +const struct drm_connector_funcs *funcs,
> +int connector_type,
> +struct i2c_adapter *ddc)
> +{
> +   int ret;
> +
> +   if (!(connector_type == DRM_MODE_CONNECTOR_HDMIA ||
> + connector_type == DRM_MODE_CONNECTOR_HDMIB))
> +   return -EINVAL;
> +
> +   ret = drmm_connector_init(dev, connector, funcs, connector_type, ddc);
> +   if (ret)
> +   return ret;
> +
> +   return 0;
> +}
> +EXPORT_SYMBOL(drmm_connector_hdmi_init);
> +
>  /**
>   * drm_connector_attach_edid_property - attach edid property.
>   * @connector: the connector
> diff --git a/drivers/gpu/drm/tests/drm_connector_test.c 
> b/drivers/gpu/drm/tests/drm_connector_test.c
> index a268847be8d1..8f070cacab3b 100644
> --- a/drivers/gpu/drm/tests/drm_connector_test.c
> +++ b/drivers/gpu/drm/tests/drm_connector_test.c
> @@ -172,6 +172,128 @@ static struct kunit_suite 
> drmm_connector_init_test_suite = {
> .test_cases = drmm_connector_init_tests,
>  };
>
> +/*
> + * Test that the registration of a bog standard connector works as
> + * expected and doesn't report any error.
> + */
> +static void drm_test_connector_hdmi_init_valid(struct kunit *test)
> +{
> +   struct drm_connector_init_priv *priv = test->priv;
> +   int ret;
> +
> +   ret = drmm_connector_hdmi_init(>drm, >connector,
> +  _funcs,
> +  DRM_MODE_CONNECTOR_HDMIA,
> +  >ddc);
> +   KUNIT_EXPECT_EQ(test, ret, 0);
> +}
> +
> +/*
> + * Test that the registration of a connector without a DDC adapter
> + * doesn't report any error.
>

Re: [PATCH v5 18/44] drm/vc4: hdmi: Create destroy state implementation

2023-12-12 Thread Dave Stevenson
On Thu, 7 Dec 2023 at 15:50, Maxime Ripard  wrote:
>
> Even though we were rolling our own custom state for the vc4 HDMI
> controller driver, we were still using the generic helper to destroy
> that state.
>
> It was mostly working since the underlying state is the first member of
> our state so the pointers are probably equal in all relevant cases, but
> it's still fragile so let's fix this properly.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/vc4/vc4_hdmi.c | 12 +++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> index 25c9c71256d3..f05e2c95a60d 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> @@ -672,11 +672,21 @@ vc4_hdmi_connector_duplicate_state(struct drm_connector 
> *connector)
> return _state->base;
>  }
>
> +static void vc4_hdmi_connector_destroy_state(struct drm_connector *connector,
> +struct drm_connector_state 
> *state)
> +{
> +   struct vc4_hdmi_connector_state *vc4_state =
> +   conn_state_to_vc4_hdmi_conn_state(state);
> +
> +   __drm_atomic_helper_connector_destroy_state(state);
> +   kfree(vc4_state);
> +}
> +
>  static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
> .fill_modes = drm_helper_probe_single_connector_modes,
> .reset = vc4_hdmi_connector_reset,
> .atomic_duplicate_state = vc4_hdmi_connector_duplicate_state,
> -   .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +   .atomic_destroy_state = vc4_hdmi_connector_destroy_state,
> .atomic_get_property = vc4_hdmi_connector_get_property,
> .atomic_set_property = vc4_hdmi_connector_set_property,
>  };
>
> --
> 2.43.0
>


Re: [PATCH v1 0/2] Add waveshare 7inch touchscreen panel support

2023-12-06 Thread Dave Stevenson
Hi Keith

On Wed, 6 Dec 2023 at 08:55, Keith Zhao  wrote:
>
>
>
> On 2023/11/25 0:04, Dave Stevenson wrote:
> > On Fri, 24 Nov 2023 at 15:00, Stefan Wahren  wrote:
> >>
> >> Hi Shengyang,
> >>
> >> [fix address of Emma]
> >
> > Not merged to master yet, but Emma has stepped back from maintenance.
> > https://lists.freedesktop.org/archives/dri-devel/2023-October/428829.html
> > Dropped from the cc.
> >
> >> Am 24.11.23 um 11:44 schrieb Shengyang Chen:
> >> > This patchset adds waveshare 7inch touchscreen panel support
> >> > for the StarFive JH7110 SoC.
> >> >
> >> > Patch 1 add new compatible for the raspberrypi panel driver and its 
> >> > dt-binding.
> >> > Patch 2 add new display mode and new probing process for raspberrypi 
> >> > panel driver.
> >> >
> >> > Waveshare 7inch touchscreen panel is a kind of raspberrypi panel
> >> > which can be drived by raspberrypi panel driver.
> >> >
> >> > The series has been tested on the VisionFive 2 board.
> >> surprisingly i was recently working on the official Raspberry Pi
> >> touchscreen and was able to get it running the new way.
> >>
> >> What do i mean with the new way. There is almost nothing special to the
> >> Raspberry Pi touchscreen, so we should try to use/extend existing
> >> components like:
> >>
> >> CONFIG_DRM_PANEL_SIMPLE
> >> CONFIG_TOUCHSCREEN_EDT_FT5X06
> >> CONFIG_DRM_TOSHIBA_TC358762
> >>
> >> The only special part is the Attiny on the connector PCB which requires:
> >>
> >> CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
> >>
> >> So the whole point is to avoid writing monolitic drivers for simple
> >> panel like that.
> >>
> >> There is a WIP branch based on top of Linux 6.7-rcX, which should
> >> demonstrate this approach [1]. Unfortunately it is not ready for
> >> upstreaming, but it has been tested on a Raspberry Pi 3 B Plus. Maybe
> >> this is helpful for your case.
> >>
> >> Actually i consider panel-raspberrypi-touchscreen.c as a dead end, which
> >> shouldn't be extended.
> >
> > Agreed.
> >
> > The panel control being bound in with the Atmel control has no hook
> > for the EDT5x06 touch driver to hook in and keep the power to the
> > touch controller active. When the panel disable gets called, bye bye
> > touch overlay :-(
> >
> > And I'm reading the driver change as more of a hack to get it to work
> > on your platform, not as adding support for the Waveshare panel
> > variant.
> > Waveshare deliberately cloned the behaviour of the Pi 7" panel in
> > order to make it work with the old Pi firmware drivers, so it
> > shouldn't need any significant changes. Where did the new timings come
> > from?
> >
> >   Dave
> hi Dave :
> that's means the panel driver split into 3 sub-modules:
> panel + panel_bridge + regulator.

Correct.

You'll have a fourth device in edt_ft5x06 for the touch overlay too,
which will link to the regulator driver for power control.

> I have a question: in the
> static int rpi_touchscreen_probe(struct i2c_client *i2c)
> {
> ..
>
> ver = rpi_touchscreen_i2c_read(ts, REG_ID);
> if (ver < 0) {
> dev_err(dev, "Atmel I2C read failed: %d\n", ver);
> return -ENODEV;
> }
>
> switch (ver) {
> case 0xde: /* ver 1 */
> case 0xc3: /* ver 2 */
> break;
> default:
> dev_err(dev, "Unknown Atmel firmware revision: 0x%02x\n", 
> ver);
> return -ENODEV;
> }
>
> ..
> }
> i think this "I2C read" can use to detect whether the panel is connected to 
> dsi controller.
>
> and when split the panel driver into 3 sub-modules, it seems the default way 
> is connected.
> if I drop the panel , run modetest to check the connector status , result 
> connected.
> Is there any way to detect the connection in this case?
> Thanks

I am not aware of any DSI drivers that support hotplugging, therefore
the connector state will always be connected if the device probes.

On vc4 the relevant DSI host controller has to have been enabled in
device tree and will be a required component for binding. The DSI host
controller will be waiting on the DSI peripheral driver to call
mipi_dsi_attach, which then calls component_add. If the panel or panel
regulator isn't present, then that never happens if 

Re: [PATCH v4 02/10] drm/bridge: Fix a use case in the bridge disable logic

2023-12-05 Thread Dave Stevenson
Hi Dario

On Tue, 5 Dec 2023 at 10:54, Dario Binacchi
 wrote:
>
> The patch fixes the code for finding the next bridge with the
> "pre_enable_prev_first" flag set to false. In case this condition is
> not verified, i. e. there is no subsequent bridge with the flag set to
> false, the whole bridge list is traversed, invalidating the "next"
> variable.
>
> The use of a new iteration variable (i. e. "iter") ensures that the value
> of the "next" variable is not invalidated.

We already have https://patchwork.freedesktop.org/patch/529288/ that
has been reviewed (but not applied) to resolve this. What does this
version do differently and why?

  Dave

> Fixes: 4fb912e5e190 ("drm/bridge: Introduce pre_enable_prev_first to alter 
> bridge init order")
> Co-developed-by: Michael Trimarchi 
> Signed-off-by: Michael Trimarchi 
> Signed-off-by: Dario Binacchi 
> ---
>
> (no changes since v1)
>
>  drivers/gpu/drm/drm_bridge.c | 9 +
>  1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index f66bf4925dd8..2e5781bf192e 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -662,7 +662,7 @@ void drm_atomic_bridge_chain_post_disable(struct 
> drm_bridge *bridge,
>   struct drm_atomic_state *old_state)
>  {
> struct drm_encoder *encoder;
> -   struct drm_bridge *next, *limit;
> +   struct drm_bridge *iter, *next, *limit;
>
> if (!bridge)
> return;
> @@ -680,14 +680,15 @@ void drm_atomic_bridge_chain_post_disable(struct 
> drm_bridge *bridge,
>  * was enabled first, so disabled last
>  */
> limit = next;
> +   iter = next;
>
> /* Find the next bridge that has NOT requested
>  * prev to be enabled first / disabled last
>  */
> -   list_for_each_entry_from(next, 
> >bridge_chain,
> +   list_for_each_entry_from(iter, 
> >bridge_chain,
>  chain_node) {
> -   if (!next->pre_enable_prev_first) {
> -   next = list_prev_entry(next, 
> chain_node);
> +   if (!iter->pre_enable_prev_first) {
> +   next = list_prev_entry(iter, 
> chain_node);
> limit = next;
> break;
> }
> --
> 2.43.0
>


Re: [PATCH v1 0/2] Add waveshare 7inch touchscreen panel support

2023-11-24 Thread Dave Stevenson
On Fri, 24 Nov 2023 at 15:00, Stefan Wahren  wrote:
>
> Hi Shengyang,
>
> [fix address of Emma]

Not merged to master yet, but Emma has stepped back from maintenance.
https://lists.freedesktop.org/archives/dri-devel/2023-October/428829.html
Dropped from the cc.

> Am 24.11.23 um 11:44 schrieb Shengyang Chen:
> > This patchset adds waveshare 7inch touchscreen panel support
> > for the StarFive JH7110 SoC.
> >
> > Patch 1 add new compatible for the raspberrypi panel driver and its 
> > dt-binding.
> > Patch 2 add new display mode and new probing process for raspberrypi panel 
> > driver.
> >
> > Waveshare 7inch touchscreen panel is a kind of raspberrypi panel
> > which can be drived by raspberrypi panel driver.
> >
> > The series has been tested on the VisionFive 2 board.
> surprisingly i was recently working on the official Raspberry Pi
> touchscreen and was able to get it running the new way.
>
> What do i mean with the new way. There is almost nothing special to the
> Raspberry Pi touchscreen, so we should try to use/extend existing
> components like:
>
> CONFIG_DRM_PANEL_SIMPLE
> CONFIG_TOUCHSCREEN_EDT_FT5X06
> CONFIG_DRM_TOSHIBA_TC358762
>
> The only special part is the Attiny on the connector PCB which requires:
>
> CONFIG_REGULATOR_RASPBERRYPI_TOUCHSCREEN_ATTINY
>
> So the whole point is to avoid writing monolitic drivers for simple
> panel like that.
>
> There is a WIP branch based on top of Linux 6.7-rcX, which should
> demonstrate this approach [1]. Unfortunately it is not ready for
> upstreaming, but it has been tested on a Raspberry Pi 3 B Plus. Maybe
> this is helpful for your case.
>
> Actually i consider panel-raspberrypi-touchscreen.c as a dead end, which
> shouldn't be extended.

Agreed.

The panel control being bound in with the Atmel control has no hook
for the EDT5x06 touch driver to hook in and keep the power to the
touch controller active. When the panel disable gets called, bye bye
touch overlay :-(

And I'm reading the driver change as more of a hack to get it to work
on your platform, not as adding support for the Waveshare panel
variant.
Waveshare deliberately cloned the behaviour of the Pi 7" panel in
order to make it work with the old Pi firmware drivers, so it
shouldn't need any significant changes. Where did the new timings come
from?

  Dave

> Btw there are already DT overlays in mainline which seems to use the
> Raspberry Pi 7inch panel (without touch function yet) [2].
>
> [1] - https://github.com/lategoodbye/rpi-zero/commits/v6.7-7inch-ts
> [2] -
> https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/arch/arm64/boot/dts/freescale/imx8mm-venice-gw72xx-0x-rpidsi.dtso?h=v6.6.2=6b4da1354fd81adace0cda448c77d8f2a47d8474
>
> >
> > Shengyang Chen (2):
> >dt-bindings: display: panel: raspberrypi: Add compatible property for
> >  waveshare 7inch touchscreen panel
> >gpu: drm: panel: raspberrypi: add new display mode and new probing
> >  process
> >
> >   .../panel/raspberrypi,7inch-touchscreen.yaml  |  4 +-
> >   .../drm/panel/panel-raspberrypi-touchscreen.c | 99 ---
> >   2 files changed, 91 insertions(+), 12 deletions(-)
> >
>


Re: [RFC PATCH 2/2] vc4: introduce DMA-BUF heap

2023-11-09 Thread Dave Stevenson
Hi Simon

On Thu, 9 Nov 2023 at 17:46, Simon Ser  wrote:
>
> On Thursday, November 9th, 2023 at 16:42, Dave Stevenson 
>  wrote:
>
> > > > - What would be a good name for the heap? "vc4" is maybe a bit naive and
> > > >   not precise enough. Something with "cma"? Do we need to plan a naming
> > > >   scheme to accomodate for multiple vc4 devices?
> > >
> > > That's a general issue though that happens with pretty much all devices
> > > with a separate node for modesetting and rendering, so I don't think
> > > addressing it only for vc4 make sense, we should make it generic.
> > >
> > > So maybe something like "scanout"?
> > >
> > > One thing we need to consider too is that the Pi5 will have multiple
> > > display nodes (4(?) iirc) with different capabilities, vc4 being only
> > > one of them. This will impact that solution too.
> >
> > It does need to scale.
> >
> > Pi5 adds 4 additional DRM devices (2xDSI, 1xDPI, and 1xComposite
> > Video), and just this last week I've been running Wayfire with TinyDRM
> > drivers for SPI displays and UDL (DisplayLink) outputs as well.
> > Presumably all of those drivers need to have appropriate hooks added
> > so they each expose a dma-heap to enable scanout buffers to be
> > allocated.
>
> I'm not sure this makes sense necessarily for all of these devices. For vc4 
> and
> the 4 additional RPi 5 DRM devices, probably. For the rest, e.g. UDL, I'm not
> sure it makes sense to expose scanout memory allocation via DMA heaps: AFAIK
> UDL needs CPU access to the buffers, it can't "scanout", and thus directly
> rendering via v3d to a "scanout-capable" buffer doesn't make sense. There will
> be a copy (CPU download) either way, and allocating via v3d wouldn't make a
> difference.

You as a developer may know that UDL is going to need CPU access, but
how does a generic userspace app know? Is it a case of falling back to
allocating via the renderer if there is no suitably named heap?

> > Can we add another function pointer to the struct drm_driver (or
> > similar) to do the allocation, and move the actual dmabuf handling
> > code into the core?
>
> Do you mean that the new logic introduced in this patch should be in DRM core
> to allow other drivers to more easily re-use it? Or do you mean something 
> else?

Yes, make it easy to reuse between drivers.

> Indeed, there is nothing vc4-specific in this patch, the only requirement is
> that the driver uses drm_gem_dma_helper. So this code could be moved into (or
> alongside) that helper in DRM core. However, maybe it would be best to wait to
> have a second user for this infrastructure before we move into core.

Upstreaming of the DSI / DPI / composite drivers for Pi5 should only
be a few months away, and they can all directly scanout.

I expect the Rockchip platforms to also fall into the same category as
the Pi, with Mali as the 3D IP, and the VOP block as the scanout
engine. Have I missed some detail that means that they aren't a second
user for this?

> > > > - Need to add !vc5 support.
> > >
> > > If by !vc5 you mean RPi0-3, then it's probably not needed there at all
> > > since it has a single node for both modesetting and rendering?
> >
> > That is true, but potentially vc4 could be rendering for scanout via UDL or 
> > SPI.
> > Is it easier to always have the dma-heap allocator for every DRM card
> > rather than making userspace mix and match depending on whether it is
> > all in one vs split?
>
> I don't think it's realistic to try to always make DMA heaps available for 
> each
> and every driver which might need it from day one. It's too big of a task. And
> it's an even bigger task to try to design a fully generic heap compatibility
> uAPI from day one. I'd much rather add the heaps one by one, if and when we
> figure that it makes sense, and incrementally work our way through.

Is it really that massive a task? We have the dma heap UAPI for
handling the allocations, so what new UAPI is required?

If it's a new function pointer in struct drm_driver, then the heap is
only created by the core if that function is defined using the driver
name. The function returns a struct dma_buf *.
Any driver using drm_gem_dma_helper can use the new helper function
that is basically your vc4_dma_heap_allocate. The "if
(WARN_ON_ONCE(!vc4->is_vc5))" could be handled by not setting the
function pointer on those platforms.

Sorry, I feel I must be missing some critical piece of information here.

  Dave


Re: [RFC PATCH 2/2] vc4: introduce DMA-BUF heap

2023-11-09 Thread Dave Stevenson
Hi Simon and Maxime

On Thu, 9 Nov 2023 at 09:12, Maxime Ripard  wrote:
>
> Hi Simon,
>
> On Thu, Nov 09, 2023 at 07:45:58AM +, Simon Ser wrote:
> > User-space sometimes needs to allocate scanout-capable memory for
> > GPU rendering purposes. On a vc4/v3d split render/display SoC, this
> > is achieved via DRM dumb buffers: the v3d user-space driver opens
> > the primary vc4 node, allocates a DRM dumb buffer there, exports it
> > as a DMA-BUF, imports it into the v3d render node, and renders to it.
> >
> > However, DRM dumb buffers are only meant for CPU rendering, they are
> > not intended to be used for GPU rendering. Primary nodes should only
> > be used for mode-setting purposes, other programs should not attempt
> > to open it. Moreover, opening the primary node is already broken on
> > some setups: systemd grants permission to open primary nodes to
> > physically logged in users, but this breaks when the user is not
> > physically logged in (e.g. headless setup) and when the distribution
> > is using a different init (e.g. Alpine Linux uses openrc).
> >
> > We need an alternate way for v3d to allocate scanout-capable memory.
> > Leverage DMA heaps for this purpose: expose a CMA heap to user-space.
> > Preliminary testing has been done with wlroots [1].
> >
> > This is still an RFC. Open questions:
> >
> > - Does this approach make sense to y'all in general?
>
> Makes sense to me :)
>
> > - What would be a good name for the heap? "vc4" is maybe a bit naive and
> >   not precise enough. Something with "cma"? Do we need to plan a naming
> >   scheme to accomodate for multiple vc4 devices?
>
> That's a general issue though that happens with pretty much all devices
> with a separate node for modesetting and rendering, so I don't think
> addressing it only for vc4 make sense, we should make it generic.
>
> So maybe something like "scanout"?
>
> One thing we need to consider too is that the Pi5 will have multiple
> display nodes (4(?) iirc) with different capabilities, vc4 being only
> one of them. This will impact that solution too.

It does need to scale.

Pi5 adds 4 additional DRM devices (2xDSI, 1xDPI, and 1xComposite
Video), and just this last week I've been running Wayfire with TinyDRM
drivers for SPI displays and UDL (DisplayLink) outputs as well.
Presumably all of those drivers need to have appropriate hooks added
so they each expose a dma-heap to enable scanout buffers to be
allocated.

Can we add another function pointer to the struct drm_driver (or
similar) to do the allocation, and move the actual dmabuf handling
code into the core?

> > - Right now root privileges are necessary to open the heap. Should we
> >   allow everybody to open the heap by default (after all, user-space can
> >   already allocate arbitrary amounts of GPU memory)? Should we leave it
> >   up to user-space to solve this issue (via logind/seatd or a Wayland
> >   protocol or something else)?
>
> I would have expected a udev rule to handle that?
>
> > TODO:
> >
> > - Need to add !vc5 support.
>
> If by !vc5 you mean RPi0-3, then it's probably not needed there at all
> since it has a single node for both modesetting and rendering?

That is true, but potentially vc4 could be rendering for scanout via UDL or SPI.
Is it easier to always have the dma-heap allocator for every DRM card
rather than making userspace mix and match depending on whether it is
all in one vs split?

  Dave


Re: [PATCH] drm/vc4: fix typo

2023-10-23 Thread Dave Stevenson
Hi Dario

Thanks for the patch.

On Mon, 23 Oct 2023 at 09:59, Dario Binacchi
 wrote:
>
> Replace 'pack' with 'back'.
>
> Fixes: c8b75bca92cb ("drm/vc4: Add KMS support for Raspberry Pi.")
> Signed-off-by: Dario Binacchi 

Reviewed-by: Dave Stevenson 

> ---
>
>  drivers/gpu/drm/vc4/vc4_regs.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
> index f3763bd600f6..8ac9515554f8 100644
> --- a/drivers/gpu/drm/vc4/vc4_regs.h
> +++ b/drivers/gpu/drm/vc4/vc4_regs.h
> @@ -588,7 +588,7 @@ enum {
>  # define VC4_HDMI_HORZA_HAP_MASK   VC4_MASK(12, 0)
>  # define VC4_HDMI_HORZA_HAP_SHIFT  0
>
> -/* Horizontal pack porch (htotal - hsync_end). */
> +/* Horizontal back porch (htotal - hsync_end). */
>  # define VC4_HDMI_HORZB_HBP_MASK   VC4_MASK(29, 20)
>  # define VC4_HDMI_HORZB_HBP_SHIFT  20
>  /* Horizontal sync pulse (hsync_end - hsync_start). */
> --
> 2.42.0
>


Re: DRM FB emulation initialisation leaving the display disabled

2023-10-13 Thread Dave Stevenson
Hi Thomas

Thanks for the response.

On Thu, 12 Oct 2023 at 08:03, Thomas Zimmermann  wrote:
>
> Hi Dave
>
> Am 11.10.23 um 17:52 schrieb Dave Stevenson:
> > Hi Thomas (and everyone else)
> >
> > Maxime has suggested you're the person for DRM framebuffer emulation.
> >
> > I'm getting some unexpected behaviour when there are multiple DRM
> > drivers in play. In this case it happens to be vc4 and the tiny
> > hx8357d SPI display driver, but this affects most of the tiny DRM
> > drivers and also the DSI and DPI outputs on the Pi5.
> > We get different behaviour depending on whether vc4 or hx8357d
> > initialises first.
> >
> > If hx8357d loads first and registers as /dev/fb0 through the fb
> > emulation, then we get fbcon enabling the display and putting the
> > emulated framebuffer on it. vc4 then loads, registers /dev/fb1, and
> > through the hotplug handler it enables the display
> > (drm_fb_helper_hotplug_event calls, drm_fb_helper_set_par, which calls
> > __drm_fb_helper_restore_fbdev_mode_unlocked).
> >
> > If vc4 loads first and claims /dev/fb0, fbcon initalises and enables
> > the display. hx8357d then loads and registers as /dev/fb1. fbcon is
> > not configured for that fb, and there is no subsequent hotplug event
> > (SPI displays aren't hotpluggable), so we have a fully configured
> > framebuffer exposed to userspace but the display itself isn't enabled
> > so we don't see anything :-(
> > Open and close /dev/dri/card1 and the lastclose hook calls
> > drm_fb_helper_restore_fbdev_mode_unlocked and we get the display
> > enabled.
>
> What you're describing sounds like the recent bug report at
>
>https://gitlab.freedesktop.org/drm/amd/-/issues/2649
>
> which had similar symptoms with amdgpu. IIRC the console didn't
> initialize if the DRM hotplugging event happened before fbdev emulation
> was ready. DRM's fbdev code would then not see the hotplugged connector.
>
> Do you have commit 27655b9bb9f0 ("drm/client: Send hotplug event after
> registering a client") in your tree? (It's been ported into various
> stable branches as well.)

I was about to switch from my 6.1.55 build to the latest just to
ensure it hadn't been fixed, but that commit hit the 6.1 stable branch
in 6.1.43, so I do have it.

Other priorities have overtaken my investigation of this, but at least
knowing that it should enable the outputs (and nominally through the
hotplug hook) I can have another look at what is actually going on.

Thanks again
  Dave

> Best regard
> Thomas
>
> >
> > Is it intentional that we're left in this limbo state with the display
> > not enabled if fbcon isn't enabled on a framebuffer?
> >
> > We're trying to get people to transition from the fbdev drivers to DRM
> > equivalents, but this seems to be a backwards step if there is an
> > extra step required to get the display enabled. Many users are still
> > just using the framebuffer.
> >
> > Any input is much appreciated.
> >
> > Thanks,
> >Dave
>
> --
> Thomas Zimmermann
> Graphics Driver Developer
> SUSE Software Solutions Germany GmbH
> Frankenstrasse 146, 90461 Nuernberg, Germany
> GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
> HRB 36809 (AG Nuernberg)


DRM FB emulation initialisation leaving the display disabled

2023-10-11 Thread Dave Stevenson
Hi Thomas (and everyone else)

Maxime has suggested you're the person for DRM framebuffer emulation.

I'm getting some unexpected behaviour when there are multiple DRM
drivers in play. In this case it happens to be vc4 and the tiny
hx8357d SPI display driver, but this affects most of the tiny DRM
drivers and also the DSI and DPI outputs on the Pi5.
We get different behaviour depending on whether vc4 or hx8357d
initialises first.

If hx8357d loads first and registers as /dev/fb0 through the fb
emulation, then we get fbcon enabling the display and putting the
emulated framebuffer on it. vc4 then loads, registers /dev/fb1, and
through the hotplug handler it enables the display
(drm_fb_helper_hotplug_event calls, drm_fb_helper_set_par, which calls
__drm_fb_helper_restore_fbdev_mode_unlocked).

If vc4 loads first and claims /dev/fb0, fbcon initalises and enables
the display. hx8357d then loads and registers as /dev/fb1. fbcon is
not configured for that fb, and there is no subsequent hotplug event
(SPI displays aren't hotpluggable), so we have a fully configured
framebuffer exposed to userspace but the display itself isn't enabled
so we don't see anything :-(
Open and close /dev/dri/card1 and the lastclose hook calls
drm_fb_helper_restore_fbdev_mode_unlocked and we get the display
enabled.

Is it intentional that we're left in this limbo state with the display
not enabled if fbcon isn't enabled on a framebuffer?

We're trying to get people to transition from the fbdev drivers to DRM
equivalents, but this seems to be a backwards step if there is an
extra step required to get the display enabled. Many users are still
just using the framebuffer.

Any input is much appreciated.

Thanks,
  Dave


Re: [PATCH] drm/panel: Add prepare_prev_first flag to Visionox VTDR6130

2023-08-29 Thread Dave Stevenson
Hi Neil

On Mon, 28 Aug 2023 at 09:49,  wrote:
>
> Hi Jessica,
>
> On 25/08/2023 20:37, Jessica Zhang wrote:
> >
> >
> > On 8/21/2023 3:01 AM, neil.armstr...@linaro.org wrote:
> >> Hi Maxime,
> >>
> >> On 21/08/2023 10:17, Maxime Ripard wrote:
> >>> Hi,
> >>>
> >>> On Fri, Aug 18, 2023 at 10:25:48AM +0200, neil.armstr...@linaro.org wrote:
>  On 17/08/2023 20:35, Dmitry Baryshkov wrote:
> > On 16/08/2023 10:51, neil.armstr...@linaro.org wrote:
> >> Sending HS commands will always work on any controller, it's all
> >> about LP commands. The Samsung panels you listed only send HS
> >> commands so they can use prepare_prev_first and work on any
> >> controllers.
> >
> > I think there is some misunderstanding there, supported by the
> > description of the flag.
> >
> > If I remember correctly, some hosts (sunxi) can not send DCS
> > commands after enabling video stream and switching to HS mode, see
> > [1]. Thus, as you know, most of the drivers have all DSI panel setup
> > commands in drm_panel_funcs::prepare() /
> > drm_bridge_funcs::pre_enable() callbacks, not paying attention
> > whether these commands are to be sent in LP or in HS mode.
> >
> > Previously DSI source drivers could power on the DSI link either in
> > mode_set() or in pre_enable() callbacks, with mode_set() being the
> > hack to make panel/bridge drivers to be able to send commands from
> > their prepare() / pre_enable() callbacks.
> >
> > With the prev_first flags being introduced, we have established that
> > DSI link should be enabled in DSI host's pre_enable() callback and
> > switched to HS mode (be it command or video) in the enable()
> > callback.
> >
> > So far so good.
> 
>  It seems coherent, I would like first to have a state of all DSI host
>  drivers and make this would actually work first before adding the
>  prev_first flag to all the required panels.
> >>>
> >>> This is definitely what we should do in an ideal world, but at least for
> >>> sunxi there's no easy way for it at the moment. There's no documentation
> >>> for it and the driver provided doesn't allow this to happen.
> >>>
> >>> Note that I'm not trying to discourage you or something here, I'm simply
> >>> pointing out that this will be something that we will have to take into
> >>> account. And it's possible that other drivers are in a similar
> >>> situation.
> >>>
> > Unfortunately this change is not fully backwards-compatible. This
> > requires that all DSI panels sending commands from prepare() should
> > have the prepare_prev_first flag. In some sense, all such patches
> > might have Fixes: 5ea6b1702781 ("drm/panel: Add prepare_prev_first
> > flag to drm_panel").
> 
>  This kind of migration should be done *before* any possible
>  regression, not the other way round.
> 
>  If all panels sending commands from prepare() should have the
>  prepare_prev_first flag, then it should be first, check for
>  regressions then continue.
> 
>  
> 
> >>
> >> I understand, but this patch doesn't qualify as a fix for
> >> 9e15123eca79 and is too late to be merged in drm-misc-next for
> >> v6.6, and since 9e15123eca79 actually breaks some support it
> >> should be reverted (+ deps) since we are late in the rc cycles.
> >
> > If we go this way, we can never reapply these patches. There will be
> > no guarantee that all panel drivers are completely converted. We
> > already have a story without an observable end -
> > DRM_BRIDGE_ATTACH_NO_CONNECTOR.
> 
>  I don't understand this point, who would block re-applying the patches ?
> 
>  The migration to DRM_BRIDGE_ATTACH_NO_CONNECTOR was done over multiple
>  Linux version and went smoothly because we reverted regressing patches
>  and restarted when needed, I don't understand why we can't do this
>  here aswell.
> 
> > I'd consider that the DSI driver is correct here and it is about the
> > panel drivers that require fixes patches. If you care about the
> > particular Fixes tag, I have provided one several lines above.
> 
>  Unfortunately it should be done in the other way round, prepare for
>  migration, then migrate,
> 
>  I mean if it's a required migration, then it should be done and I'll
>  support it from both bridge and panel PoV.
> 
>  So, first this patch has the wrong Fixes tag, and I would like a
>  better explanation on the commit message in any case. Then I would
>  like to have an ack from some drm-misc maintainers before applying it
>  because it fixes a patch that was sent via the msm tree thus per the
>  drm-misc rules I cannot apply it via the drm-misc-next-fixes tree.
> >>>
> >>> Sorry, it's not clear to me what you'd like our feedback on exactly?
> >>
> >> So let me resume the situation:
> >>
> >> 

Re: [PATCH] drm/panel/panel-sitronix-st7701: Move init sequence from prepare() to enable()

2023-08-29 Thread Dave Stevenson
Hi Marek & Mimoja

On Sat, 26 Aug 2023 at 22:02, Marek Vasut  wrote:
>
> On 8/26/23 20:33, Mimoja wrote:
>
> Hi,
>
> +CC Dave , he might be able to help with the last part.
>
> > I appreciate you taking the time to respond!
> >
> > On 26.08.23 17:18, Marek Vasut wrote:
> >> On 8/26/23 11:55, Mimoja wrote:
> >>> "The .prepare() function is typically called before the display
> >>> controller
> >>> starts to transmit video data."
> >>> and
> >>> "After the display controller has started transmitting video data,
> >>> it's safe
> >>>   to call the .enable() function."
> >>
> >> DSI commands are not DSI video, so this should be OK ?
> >
> > You are correct, my commit message is mixing things up here. I wanted to
> > emphasize roughly the thought of
> > "when enable() is called the dsi core is expected to have its clock
> > initialized". Will take note to clarify this if I succeed to
> > make a case for this patch below :)
>
> I vaguely recall there was this flag in include/drm/drm_bridge.h which
> might be related:
>
> 748 /**
> 749  * @pre_enable_prev_first: The bridge requires that the prev
> 750  * bridge @pre_enable function is called before its @pre_enable,
> 751  * and conversely for post_disable. This is most frequently a
> 752  * requirement for DSI devices which need the host to be initialised
> 753  * before the peripheral.
> 754  */
> 755 bool pre_enable_prev_first;
>
> Could it be, this is what you need ?

drm_panel has prepare_prev_first, which maps to drm_bridge's
pre_enable_prev_first, but same concept.
Most likely this is what you're after, but only got added in 6.3.

> >>> While generally fine this can lead to a fillup of the transmission
> >>> queue before
> >>> the transmission is set up on certain dsi bridges.
> >>> This issue can also be seen on downstream imx8m* kernels.
> >>
> >> Can you reproduce this with current mainline Linux or linux-next tree ?
> >> I recall the display pipeline in the NXP downstream stuff is very
> >> different from mainline .
> >
> > You are very much correct. The NXP downstream kernel is completely
> > different from the upstream one
> > and is really a great example to show the issue (code cleaned up for
> > readability):
> >
> > https://github.com/varigit/linux-imx/blob/5.15-2.0.x-imx_var01/drivers/gpu/drm/bridge/sec-dsim.c#L1368
> > ```
> >  ret = drm_panel_prepare(dsim->panel);
> >  if (unlikely(ret)) [...]
> >
> >  /* config esc clock, byte clock and etc */
> >  sec_mipi_dsim_config_clkctrl(dsim);
> >
> >  ret = drm_panel_enable(dsim->panel);
> >  if (unlikely(ret)) [...]
> >
> > ```

That DSI host driver looks very strange, or perhaps just outdated. It
implements atomic_enable and atomic_disable, but not atomic_pre_enable
or atomic_post_disable. Any attached panel or bridge drivers therefore
don't get called in the expected way by the bridge chain.
You are on 5.15 which may predate some of the reworking, but should
still support panel_bridge so that calling one of the of_get_bridge
functions gives you a bridge irregardless of whether it is a bridge or
panel. I'd question why the DSI host driver is making calls down the
bridge chain for itself - either it results in calling functions
multiple times, or you break the bridge chain (as vc4 used to do) but
mess up atomic states as the core can't add the state of the removed
nodes.

> >
> >> Which SoC does have this problem ?
> > Sadly I don't have any SoCs available which would work perfectly with
> > linux-next, let alone are confirmed affected :/
> >
> > I were able to make my Kingway Panel work (Custom one and so far
> > unsupported by the st7701 driver) with this
> > patch on downstream 5.4 and 5.15 imx8mn as well as on a raspberry pi CM4
> > with 6.1. However raspberrypi/linux brings
> > SPI support to the st7701 driver which should not affect this but I
> > would just like to document it here.

DPI video with SPI for configuration was added to the Pi kernel to
support the Pimoroni HyperPixel 2 round display[1].

If you have the panel attached to a CM4, and prepare_prev_first is
set, then I would expect it to work on the Pi.
The docs[2] state that transfer can be called in any state, however I
know that is an issue in vc4 that I need to address at some point. If
fixed, then no change should be required.

[1] https://shop.pimoroni.com/products/hyperpixel-round?variant=39381081882707
[2] 
https://github.com/torvalds/linux/blob/master/include/drm/drm_mipi_dsi.h#L84-L87

> > I could not find any success story with st7701 and the rpi on 6.1 online
> > after a short search (and only one
> > reference with 5.10 which seems to me a bit different in a short
> > comparison)  but again I can only offer
> > circumstantial evidence. Sorry :/
>
> Maybe Dave can help with this part .

I don't recall having had an ST7701 panel using DSI, so I'm afraid I
can't really help there.

  Dave


Re: [PATCH] drm/panel: Add prepare_prev_first flag to Visionox VTDR6130

2023-08-21 Thread Dave Stevenson
Hi Dmitry

On Fri, 18 Aug 2023 at 11:27, Dmitry Baryshkov
 wrote:
>
> On 18/08/2023 11:25, neil.armstr...@linaro.org wrote:
> > Hi Dmitry,
> >
> > On 17/08/2023 20:35, Dmitry Baryshkov wrote:
> >> On 16/08/2023 10:51, neil.armstr...@linaro.org wrote:
> >>> Hi Abhinav,
> >>>
> >>> On 14/08/2023 20:02, Abhinav Kumar wrote:
> >
> > 
> >
> >>>
> >>> Sending HS commands will always work on any controller, it's all
> >>> about LP commands.
> >>> The Samsung panels you listed only send HS commands so they can use
> >>> prepare_prev_first
> >>> and work on any controllers.
> >>
> >> I think there is some misunderstanding there, supported by the
> >> description of the flag.
> >>
> >> If I remember correctly, some hosts (sunxi) can not send DCS commands
> >> after enabling video stream and switching to HS mode, see [1]. Thus,
> >> as you know, most of the drivers have all DSI panel setup commands in
> >> drm_panel_funcs::prepare() / drm_bridge_funcs::pre_enable() callbacks,
> >> not paying attention whether these commands are to be sent in LP or in
> >> HS mode.
> >>
> >> Previously DSI source drivers could power on the DSI link either in
> >> mode_set() or in pre_enable() callbacks, with mode_set() being the
> >> hack to make panel/bridge drivers to be able to send commands from
> >> their prepare() / pre_enable() callbacks.
> >>
> >> With the prev_first flags being introduced, we have established that
> >> DSI link should be enabled in DSI host's pre_enable() callback and
> >> switched to HS mode (be it command or video) in the enable() callback.
> >>
> >> So far so good.
> >
> > It seems coherent, I would like first to have a state of all DSI host
> > drivers and make this would actually work first before adding the
> > prev_first flag to all the required panels.
> >
> >>
> >> Unfortunately this change is not fully backwards-compatible. This
> >> requires that all DSI panels sending commands from prepare() should
> >> have the prepare_prev_first flag. In some sense, all such patches
> >> might have Fixes: 5ea6b1702781 ("drm/panel: Add prepare_prev_first
> >> flag to drm_panel").
> >
> > This kind of migration should be done *before* any possible regression,
> > not the other way round.
> >
> > If all panels sending commands from prepare() should have the
> > prepare_prev_first flag, then it should be first, check for regressions
> > then continue.
> >
> > 
> >
> >>>
> >>> I understand, but this patch doesn't qualify as a fix for
> >>> 9e15123eca79 and is too late to be merged in drm-misc-next for v6.6,
> >>> and since 9e15123eca79 actually breaks some support it should be
> >>> reverted (+ deps) since we are late in the rc cycles.
> >>
> >> If we go this way, we can never reapply these patches. There will be
> >> no guarantee that all panel drivers are completely converted. We
> >> already have a story without an observable end -
> >> DRM_BRIDGE_ATTACH_NO_CONNECTOR.
> >
> > I don't understand this point, who would block re-applying the patches ?
>
> Consider us reverting 9e15123eca79 now and then reapplying it next
> cycle. Then another panel / bridge that was not converted to use
> pre_enable_prev_first pops up. And suddently we have to revert them again.
>
> > The migration to DRM_BRIDGE_ATTACH_NO_CONNECTOR was done over multiple
> > Linux version and went smoothly because we reverted
> > regressing patches and restarted when needed, I don't understand why we
> > can't do this here aswell.
>
> With DRM_BRIDGE_ATTACH_NO_CONNECTOR both host and peripheral drivers
> were involved. This way they share knowledge about the migration state.
>
> With prev_first we do not have such shared knowledge. Host assumes that
> it can work according to the documentation: turn DSI link to LP-11 in
> pre_enable(), switch to HS in enable(). It can not check whether the
> next bridge did not set pre_enable_prev_first because of it not being
> required (like for the Parade bridge) or because next bridge is not
> converted yet (and thus DSI host should power up the link in
> atomic_mode_set).
>
> Granted that there is no way for the DSI host driver to attune itself to
> the DSI peripheral driver requirements, I can only consider
> corresponding (requiring prev_first) panel drivers broken since
> 5ea6b1702781 ("drm/panel: Add prepare_prev_first flag to drm_panel") and
> all bridge drivers with this issue broken since 4fb912e5e190
> ("drm/bridge: Introduce pre_enable_prev_first to alter bridge init order").

Can I point out that even prior to 5ea6b1702781 the docs stated [1]

"Also note that those callbacks can be called no matter the state the
host is in. Drivers that need the underlying device to be powered to
perform these operations will first need to make sure it’s been
properly enabled."

added in bacbab58f09dc. So your DSI host driver isn't working in the
documented manner prior to 5ea6b1702781, therefore 5ea6b1702781
doesn't cause a regression in itself, and there was no direct
requirement for 5ea6b1702781 to add the flag to 

Re: [PATCH RFC 10/13] drm/connector: hdmi: Add Infoframes generation

2023-08-15 Thread Dave Stevenson
Hi Maxime

On Mon, 14 Aug 2023 at 14:56, Maxime Ripard  wrote:
>
> Infoframes in KMS is usually handled by a bunch of low-level helpers
> that require quite some boilerplate for drivers. This leads to
> discrepancies with how drivers generate them, and which are actually
> sent.
>
> Now that we have everything needed to generate them in the HDMI
> connector state, we can generate them in our common logic so that
> drivers can simply reuse what we precomputed.
>
> Signed-off-by: Maxime Ripard 
> ---
>  drivers/gpu/drm/drm_hdmi_connector.c | 287 
> +++
>  include/drm/drm_connector.h  | 100 
>  2 files changed, 387 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_hdmi_connector.c 
> b/drivers/gpu/drm/drm_hdmi_connector.c
> index 22c49906dfb5..46cafb17def7 100644
> --- a/drivers/gpu/drm/drm_hdmi_connector.c
> +++ b/drivers/gpu/drm/drm_hdmi_connector.c
> @@ -5,8 +5,10 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
> +#include 
>
>  #include 
>
> @@ -499,6 +501,131 @@ drm_hdmi_connector_compute_config(const struct 
> drm_hdmi_connector *hdmi_connecto
> return -EINVAL;
>  }
>
> +static int
> +drm_hdmi_connector_generate_avi_infoframe(const struct drm_hdmi_connector 
> *hdmi_connector,
> + struct drm_hdmi_connector_state 
> *hdmi_state)
> +{
> +   const struct drm_connector *connector = _connector->base;
> +   const struct drm_connector_state *state = _state->base;
> +   const struct drm_display_mode *mode =
> +   connector_state_get_adjusted_mode(state);
> +   struct hdmi_avi_infoframe *frame = _state->infoframes.avi;
> +   bool is_lim_range =
> +   drm_atomic_helper_hdmi_connector_is_full_range(hdmi_connector,
> +  hdmi_state);
> +   enum hdmi_quantization_range rgb_quant_range =
> +   is_lim_range ? HDMI_QUANTIZATION_RANGE_FULL : 
> HDMI_QUANTIZATION_RANGE_LIMITED;
> +   int ret;
> +
> +   ret = drm_hdmi_avi_infoframe_from_display_mode(frame, connector, 
> mode);
> +   if (ret)
> +   return ret;
> +
> +   frame->colorspace = hdmi_state->output_format;
> +
> +   drm_hdmi_avi_infoframe_quant_range(frame, connector, mode, 
> rgb_quant_range);
> +   drm_hdmi_avi_infoframe_colorimetry(frame, state);
> +   drm_hdmi_avi_infoframe_bars(frame, state);
> +
> +   return 0;
> +}
> +
> +static int
> +drm_hdmi_connector_generate_spd_infoframe(const struct drm_hdmi_connector 
> *hdmi_connector,
> + struct drm_hdmi_connector_state 
> *hdmi_state)
> +{
> +   struct hdmi_spd_infoframe *frame = _state->infoframes.spd;
> +   int ret;
> +
> +   ret = hdmi_spd_infoframe_init(frame,
> + hdmi_connector->vendor,
> + hdmi_connector->product);
> +   if (ret)
> +   return ret;
> +
> +   frame->sdi = HDMI_SPD_SDI_PC;
> +
> +   return 0;
> +}
> +
> +static int
> +drm_hdmi_connector_generate_hdr_infoframe(const struct drm_hdmi_connector 
> *hdmi_connector,
> + struct drm_hdmi_connector_state 
> *hdmi_state)
> +{
> +   const struct drm_connector_state *state = _state->base;
> +   struct hdmi_drm_infoframe *frame = _state->infoframes.drm;
> +   int ret;
> +
> +   if (hdmi_connector->max_bpc < 10)
> +   return 0;
> +
> +   if (!state->hdr_output_metadata)
> +   return 0;

Minor issue here I think.

If bpc < 10 or hdr_output_metadata isn't defined then the infoframe
will be left at all 0's due to the state's kzalloc. However we will
still call update_infoframe and therefore write_infoframe asking for
the infoframe to be sent, but frame->any.type = 0. It is true that
frame type 0 isn't defined, but what is the driver expected to make of
that?

If frame->any.type is initialised appropriately (or type is passed
directly), then a length of 0 could be reasonably used to signal that
the infoframe should not be sent. Otherwise I don't think we have a
path which can stop sending the HDR infoframe if it has ever been
sent.

On vc4 I think it's also going to trip up as it has a buffer slot per
type, and slot 0 is used for the GCP.

Thanks
  Dave

> +
> +   ret = drm_hdmi_infoframe_set_hdr_metadata(frame, state);
> +   if (ret)
> +   return ret;
> +
> +   return 0;
> +}
> +
> +static int
> +drm_hdmi_connector_generate_vendor_infoframe(const struct drm_hdmi_connector 
> *hdmi_connector,
> +struct drm_hdmi_connector_state 
> *hdmi_state)
> +{
> +   const struct drm_connector *connector = _connector->base;
> +   const struct drm_connector_state *state = _state->base;
> +   const struct drm_display_mode *mode =
> +   

Re: [PATCH v3 02/10] drm/panel: Check for already prepared/enabled in drm_panel

2023-08-02 Thread Dave Stevenson
On Wed, 2 Aug 2023 at 18:26, Chris Morgan  wrote:
>
> * Spam *
> On Mon, Jul 31, 2023 at 07:03:07PM +0200, Maxime Ripard wrote:
> > Hi,
> >
> > On Mon, Jul 31, 2023 at 11:33:22AM -0500, Chris Morgan wrote:
> > > In my case a few different panel drivers disable the regulators in the
> > > unprepare/disable routines.
> >
> > And that's totally fine.
> >
> > > For at least the Rockchip DSI implementations for some reason the
> > > panel gets unprepared more than once, which triggers an unbalanced
> > > regulator disable.
> >
> > "For some reason" being that DW-DSI apparently finds it ok to bypass any
> > kind of abstraction and randomly calling panel functions by itself:
> >
> > https://elixir.bootlin.com/linux/v6.4.7/source/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L868
> >
> > It looks like it's fixed it current drm-misc-next though.
>
> Good, when I get a chance I will test it out with the existing panels
> I have at my disposal and submit some patches to clean them up.
>
> >
> > > Obviously though the correct course of action is to fix the reason why
> > > the panel is disabled more than once, but that's at least the root
> > > cause of this behavior on the few panels I've worked with.
> >
> > Like I said we already have a commit on the way to fix that, so it
> > shouldn't be an issue anymore.
> >
> > I stand by what I was saying earlier though, I think it's mostly
> > cargo-cult or drivers being very wrong. If anything, the DW-DSI stuff
> > made me even more convinced that we shouldn't even entertain that idea
> > :)

DW-DSI is hacking around the fact that DSI panels may want to send DCS
commands in unprepare, however the DSI host driver shuts down the
controller in the DSI bridge post_disable which gets called first.

That ordering can now be reversed with pre_enable_prev_first flag in
struct drm_bridge, or prepare_prev_first in drm_panel, hence no need
for the DSI controller to jump around the bridge chain.

  Dave

> > Maxime
>
> Thank you, and yes if a driver is doing something it shouldn't we
> shouldn't be patching around that, we should be fixing things. Thanks
> for providing me with the additional info.
>
> Chris
>


Re: [PATCH v2 2/2] drm/bridge: Document bridge init order with pre_enable_prev_first

2023-08-01 Thread Dave Stevenson
On Tue, 28 Mar 2023 at 18:08, Jagan Teki  wrote:
>
> In order to satisfy the MIPI DSI initialization sequence the bridge
> init order has been altered with the help of pre_enable_prev_first
> in pre_enable and post_disable bridge operations.
>
> Document the affected bridge init order with an example on the
> bridge operations helpers.
>
> Signed-off-by: Jagan Teki 

Reviewed-by: Dave Stevenson 

> ---
> Changes for v2:
> - add missing dri-devel in CC
> - prefix @ for bridge helper names
>
>  drivers/gpu/drm/drm_bridge.c | 14 ++
>  1 file changed, 14 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 052a8e6c9961..caf0f341e524 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -654,6 +654,13 @@ static void drm_atomic_bridge_call_post_disable(struct 
> drm_bridge *bridge,
>   * bridge will be called before the previous one to reverse the @pre_enable
>   * calling direction.
>   *
> + * Example:
> + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E
> + *
> + * With pre_enable_prev_first flag enable in Bridge B, D, E then the 
> resulting
> + * @post_disable order would be,
> + * Bridge B, Bridge A, Bridge E, Bridge D, Bridge C.
> + *
>   * Note: the bridge passed should be the one closest to the encoder
>   */
>  void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
> @@ -750,6 +757,13 @@ static void drm_atomic_bridge_call_pre_enable(struct 
> drm_bridge *bridge,
>   * If a bridge sets @pre_enable_prev_first, then the pre_enable for the
>   * prev bridge will be called before pre_enable of this bridge.
>   *
> + * Example:
> + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E
> + *
> + * With pre_enable_prev_first flag enable in Bridge B, D, E then the 
> resulting
> + * @pre_enable order would be,
> + * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B.
> + *
>   * Note: the bridge passed should be the one closest to the encoder
>   */
>  void drm_atomic_bridge_chain_pre_enable(struct drm_bridge *bridge,
> --
> 2.25.1
>


Re: [PATCH v2 1/2] drm/bridge: Fix improper bridge init order with pre_enable_prev_first

2023-08-01 Thread Dave Stevenson
Hi Jagan

My apologies for dropping the ball on this one, and thanks to Frieder
for the nudge.

On Wed, 12 Apr 2023 at 07:25, Jagan Teki  wrote:
>
> Hi Dave,
>
> Added Maxime, Laurent [which I thought I added before]
>
> On Tue, Mar 28, 2023 at 10:38 PM Jagan Teki  
> wrote:
> >
> > For a given bridge pipeline if any bridge sets pre_enable_prev_first
> > flag then the pre_enable for the previous bridge will be called before
> > pre_enable of this bridge and opposite is done for post_disable.
> >
> > These are the potential bridge flags to alter bridge init order in order
> > to satisfy the MIPI DSI host and downstream panel or bridge to function.
> > However the existing pre_enable_prev_first logic with associated bridge
> > ordering has broken for both pre_enable and post_disable calls.
> >
> > [pre_enable]
> >
> > The altered bridge ordering has failed if two consecutive bridges on a
> > given pipeline enables the pre_enable_prev_first flag.
> >
> > Example:
> > - Panel
> > - Bridge 1
> > - Bridge 2 pre_enable_prev_first
> > - Bridge 3
> > - Bridge 4 pre_enable_prev_first
> > - Bridge 5 pre_enable_prev_first
> > - Bridge 6
> > - Encoder
> >
> > In this example, Bridge 4 and Bridge 5 have pre_enable_prev_first.
> >
> > The logic looks for a bridge which enabled pre_enable_prev_first flag
> > on each iteration and assigned the previou bridge to limit pointer
> > if the bridge doesn't enable pre_enable_prev_first flags.
> >
> > If control found Bridge 2 is pre_enable_prev_first then the iteration
> > looks for Bridge 3 and found it is not pre_enable_prev_first and assigns
> > it's previous Bridge 4 to limit pointer and calls pre_enable of Bridge 3
> > and Bridge 2 and assign iter pointer with limit which is Bridge 4.
> >
> > Here is the actual problem, for the next iteration control look for
> > Bridge 5 instead of Bridge 4 has iter pointer in previous iteration
> > moved to Bridge 4 so this iteration skips the Bridge 4. The iteration
> > found Bridge 6 doesn't pre_enable_prev_first flags so the limit assigned
> > to Encoder. From next iteration Encoder skips as it is the last bridge
> > for reverse order pipeline.
> >
> > So, the resulting pre_enable bridge order would be,
> > - Panel, Bridge 1, Bridge 3, Bridge 2, Bridge 6, Bridge 5.
> >
> > This patch fixes this by assigning limit to next pointer instead of
> > previous bridge since the iteration always looks for bridge that does
> > NOT request prev so assigning next makes sure the last bridge on a
> > given iteration what exactly the limit bridge is.
> >
> > So, the resulting pre_enable bridge order with fix would be,
> > - Panel, Bridge 1, Bridge 3, Bridge 2, Bridge 6, Bridge 5, Bridge 4,
> >   Encoder.
> >
> > [post_disable]
> >
> > The altered bridge ordering has failed if two consecutive bridges on a
> > given pipeline enables the pre_enable_prev_first flag.
> >
> > Example:
> > - Panel
> > - Bridge 1
> > - Bridge 2 pre_enable_prev_first
> > - Bridge 3
> > - Bridge 4 pre_enable_prev_first
> > - Bridge 5 pre_enable_prev_first
> > - Bridge 6
> > - Encoder
> >
> > In this example Bridge 5 and Bridge 4 have pre_enable_prev_first.
> >
> > The logic looks for a bridge which enabled pre_enable_prev_first flags
> > on each iteration and assigned the previou bridge to next and next to
> > limit pointer if the bridge does enable pre_enable_prev_first flag.
> >
> > If control starts from Bridge 6 then it found next Bridge 5 is
> > pre_enable_prev_first and immediately the next assigned to previous
> > Bridge 6 and limit assignments to next Bridge 6 and call post_enable
> > of Bridge 6 even though the next consecutive Bridge 5 is enabled with
> > pre_enable_prev_first. This clearly misses the logic to find the state
> > of next conducive bridge as everytime the next and limit assigns
> > previous bridge if given bridge enabled pre_enable_prev_first.
> >
> > So, the resulting post_disable bridge order would be,
> > - Encoder, Bridge 6, Bridge 5, Bridge 4, Bridge 3, Bridge 2, Bridge 1,
> >   Panel.
> >
> > This patch fixes this by assigning next with previou bridge only if the
> > bridge doesn't enable pre_enable_prev_first flag and the next further
> > assign it to limit. This way we can find the bridge that NOT requested
> > prev to disable last.
> >
> > So, the resulting pre_enable bridge order with fix would be,
> > - Encoder, Bridge 4, Bridge 5, Bridge 6, Bridge 2, Bridge 3, Bridge 1,
> >   Panel.
> >
> > Validated the bridge init ordering by incorporating dummy bridges in
> > the sun6i-mipi-dsi pipeline
> >
> > Fixes: 4fb912e5e190 ("drm/bridge: Introduce pre_enable_prev_first to
> > alter bridge init order")
> > Signed-off-by: Jagan Teki 

Thanks for investigating and sorting this.

Reviewed-by: Dave Stevenson 

> > ---
> > Changes for v2:
> > - add missing dri-devel in CC
>
> Would you please look into this issue?
>
> Thanks,
> Jagan.


Re: [PATCH 1/1] drm/bridge: Fix handling of bridges with pre_enable_prev_first flag

2023-07-14 Thread Dave Stevenson
Hi Frieder

On Mon, 10 Jul 2023 at 08:46, Frieder Schrempf
 wrote:
>
> On 07.07.23 21:00, Vladimir Lypak wrote:
> > [Sie erhalten nicht häufig E-Mails von vladimir.ly...@gmail.com. Weitere 
> > Informationen, warum dies wichtig ist, finden Sie unter 
> > https://aka.ms/LearnAboutSenderIdentification ]
> >
> > In function drm_atomic_bridge_chain_post_disable handling of
> > pre_enable_prev_first flag is broken because "next" variable will always
> > end up set to value of "bridge". This breaks loop which should disable
> > bridges in reverse:
> >
> >  next = list_next_entry(bridge, chain_node);
> >
> >  if (next->pre_enable_prev_first) {
> > /* next bridge had requested that prev
> >  * was enabled first, so disabled last
> >  */
> > limit = next;
> >
> > /* Find the next bridge that has NOT requested
> >  * prev to be enabled first / disabled last
> >  */
> > list_for_each_entry_from(next, >bridge_chain,
> >  chain_node) {
> > // Next condition is always true. It is likely meant to be inversed
> > // according to comment above. But doing this uncovers another problem:
> > // it won't work if there are few bridges with this flag set at the end.
> > if (next->pre_enable_prev_first) {
> > next = list_prev_entry(next, chain_node);
> > limit = next;
> > // Here we always set next = limit = branch at first iteration.
> > break;
> > }
> > }
> >
> > /* Call these bridges in reverse order */
> > list_for_each_entry_from_reverse(next, >bridge_chain,
> >  chain_node) {
> > // This loop never executes past this branch.
> > if (next == bridge)
> > break;
> >
> > drm_atomic_bridge_call_post_disable(next, old_state);
> >
> > In this patch logic for handling the flag is simplified. Temporary
> > "iter" variable is introduced instead of "next" which is used only
> > inside inner loops.
> >
> > Fixes: 4fb912e5e190 ("drm/bridge: Introduce pre_enable_prev_first to alter 
> > bridge init order")
> > Signed-off-by: Vladimir Lypak 
>
> I haven't had a chance to look at this, but I still want to reference
> another patch by Jagan that intends to fix some bug in this area:
>
> https://patchwork.kernel.org/project/dri-devel/patch/20230328170752.1102347-1-ja...@amarulasolutions.com/
>
> +Cc: Jagan
>
> Dave, as you introduced this feature, did you have a chance to look at
> Jagan's and Vladimir's patches?

Sorry, they'd fallen off my radar.
I'm having a look at the moment, but will probably need to carry it
over to Monday.

  Dave


Re: [PATCH v2] dt-bindings: display: panel: add panel-mipi-dsi-bringup

2023-05-17 Thread Dave Stevenson
Hi Paulo

On Tue, 16 May 2023 at 14:09, Paulo Pavačić  wrote:
>
> Add dt-bindings documentation for panel-mipi-dsi-bringup which currently
> supports fannal,c3004 panel. Also added fannal to vendor-prefixes.
>
> v2 changelog:
>   - revised driver title, now describes purpose
>   - revised description, now describes hw
>   - revised maintainers, now has only 1 mail
>   - removed diacritics from commit/commit author
>   - properties/compatible is now enum
>   - compatible using only lowercase
>   - revised dts example
>   - modified MAINTAINERS in this commit (instead of driver commit)
>   - dt_bindings_check checked yml
>   - checkpatch warning fixed
>
> Signed-off-by: Paulo Pavacic 
> ---
>  .../display/panel/panel-mipi-dsi-bringup.yaml | 54 +++
>  .../devicetree/bindings/vendor-prefixes.yaml  |  2 +
>  MAINTAINERS   |  6 +++
>  3 files changed, 62 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/display/panel/panel-mipi-dsi-bringup.yaml
>
> diff --git 
> a/Documentation/devicetree/bindings/display/panel/panel-mipi-dsi-bringup.yaml
> b/Documentation/devicetree/bindings/display/panel/panel-mipi-dsi-bringup.yaml
> new file mode 100644
> index ..c9e2b545657e
> --- /dev/null
> +++ 
> b/Documentation/devicetree/bindings/display/panel/panel-mipi-dsi-bringup.yaml
> @@ -0,0 +1,54 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/panel/panel-mipi-dsi-bringup.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: MIPI DSI Bringup Panel Porting Bindings
> +
> +description: |
> +  MIPI DSI Bringup Panel porting bindings to be used for a collection of 
> panels
> +  from different manufacturers which don't require backlight control from the
> +  driver and have a single reset pin which is required to be passed as an
> +  argument.

Don't we already have support for DSI displays that only need a single
reset pin via panel-simple? [1]

The bit that confuses me is that the driver patch [2] is using DSI DCS
commands to configure the panel - that differs from this dt binding
description of the panel only needing a reset pin.

Potentially there is gain in having a template DSI panel driver
available for reference, but this driver/binding appears to be trying
to act as a generic thing.

  Dave

[1] 
https://elixir.bootlin.com/linux/v6.3.2/source/drivers/gpu/drm/panel/panel-simple.c#L4605
[2] https://lists.freedesktop.org/archives/dri-devel/2023-May/404775.html


> +
> +maintainers:
> +  - Paulo Pavacic 
> +
> +allOf:
> +  - $ref: panel-common.yaml#
> +
> +properties:
> +
> +  compatible:
> +enum:
> +  # compatible must be listed in alphabetical order, ordered by 
> compatible.
> +  # The description in the comment is mandatory for each compatible.
> +
> +# Fannal 480x800 panel
> +  - fannal,c3004
> +
> +  reg: true
> +  reset-gpios: true
> +
> +required:
> +  - compatible
> +  - reg
> +  - reset-gpios
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +#include 
> +//example on IMX8MM where GPIO pin 9 is used as a reset pin
> +mipi_dsi@32e1 {
> +panel@0 {
> +compatible = "fannal,c3004";
> +reg = <0>;
> +pinctrl-0 = <_mipi_dsi_rst>;
> +pinctrl-names = "default";
> +reset-gpios = < 9 GPIO_ACTIVE_LOW>;
> +};
> +};
> +...
> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> index 82d39ab0231b..f962750f630a 100644
> --- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
> +++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
> @@ -462,6 +462,8 @@ patternProperties:
>  description: Facebook
>"^fairphone,.*":
>  description: Fairphone B.V.
> +  "^fannal,.*":
> +description: Fannal Electronics Co., Ltd
>"^faraday,.*":
>  description: Faraday Technology Corporation
>"^fastrax,.*":
> diff --git a/MAINTAINERS b/MAINTAINERS
> index e0ad886d3163..46f988ee60bd 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6566,6 +6566,12 @@ T:git git://anongit.freedesktop.org/drm/drm-misc
>  F:Documentation/devicetree/bindings/display/panel/panel-mipi-dbi-spi.yaml
>  F:drivers/gpu/drm/tiny/panel-mipi-dbi.c
>
> +DRM DRIVER FOR MIPI DSI BRINGUP
> +M:Paulo Pavacic 
> +S:Maintained
> +C:mipi-dsi-bringup:matrix.org
> +F:
> Documentation/devicetree/bindings/display/panel/panel-mipi-dsi-bringup.yaml
> +
>  DRM DRIVER FOR MSM ADRENO GPU
>  M:Rob Clark 
>  M:Abhinav Kumar 
> --
> 2.40.1
>


Re: [PATCH 52/53] drm/vc4: Convert to platform remove callback returning void

2023-05-09 Thread Dave Stevenson
On Sun, 7 May 2023 at 17:27, Uwe Kleine-König
 wrote:
>
> The .remove() callback for a platform driver returns an int which makes
> many driver authors wrongly assume it's possible to do error handling by
> returning an error code. However the value returned is (mostly) ignored
> and this typically results in resource leaks. To improve here there is a
> quest to make the remove callback return void. In the first step of this
> quest all drivers are converted to .remove_new() which already returns
> void.
>
> Trivially convert the vc4 drm drivers from always returning zero in the
> remove callback to the void returning variant.
>
> Signed-off-by: Uwe Kleine-König 

Thanks for the patch - looks good.

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/vc4/vc4_crtc.c | 5 ++---
>  drivers/gpu/drm/vc4/vc4_dpi.c  | 5 ++---
>  drivers/gpu/drm/vc4/vc4_drv.c  | 6 ++
>  drivers/gpu/drm/vc4/vc4_dsi.c  | 6 ++
>  drivers/gpu/drm/vc4/vc4_hdmi.c | 5 ++---
>  drivers/gpu/drm/vc4/vc4_hvs.c  | 5 ++---
>  drivers/gpu/drm/vc4/vc4_txp.c  | 5 ++---
>  drivers/gpu/drm/vc4/vc4_v3d.c  | 5 ++---
>  drivers/gpu/drm/vc4/vc4_vec.c  | 5 ++---
>  9 files changed, 18 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index bef9d45ef1df..7610e841ef3c 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -1450,15 +1450,14 @@ static int vc4_crtc_dev_probe(struct platform_device 
> *pdev)
> return component_add(>dev, _crtc_ops);
>  }
>
> -static int vc4_crtc_dev_remove(struct platform_device *pdev)
> +static void vc4_crtc_dev_remove(struct platform_device *pdev)
>  {
> component_del(>dev, _crtc_ops);
> -   return 0;
>  }
>
>  struct platform_driver vc4_crtc_driver = {
> .probe = vc4_crtc_dev_probe,
> -   .remove = vc4_crtc_dev_remove,
> +   .remove_new = vc4_crtc_dev_remove,
> .driver = {
> .name = "vc4_crtc",
> .of_match_table = vc4_crtc_dt_match,
> diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
> index f518d6e59ed6..e67856ae9d75 100644
> --- a/drivers/gpu/drm/vc4/vc4_dpi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dpi.c
> @@ -391,15 +391,14 @@ static int vc4_dpi_dev_probe(struct platform_device 
> *pdev)
> return component_add(>dev, _dpi_ops);
>  }
>
> -static int vc4_dpi_dev_remove(struct platform_device *pdev)
> +static void vc4_dpi_dev_remove(struct platform_device *pdev)
>  {
> component_del(>dev, _dpi_ops);
> -   return 0;
>  }
>
>  struct platform_driver vc4_dpi_driver = {
> .probe = vc4_dpi_dev_probe,
> -   .remove = vc4_dpi_dev_remove,
> +   .remove_new = vc4_dpi_dev_remove,
> .driver = {
> .name = "vc4_dpi",
> .of_match_table = vc4_dpi_dt_match,
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 0ccaee57fe9a..cee41e318bf9 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -439,11 +439,9 @@ static int vc4_platform_drm_probe(struct platform_device 
> *pdev)
> return component_master_add_with_match(dev, _drm_ops, match);
>  }
>
> -static int vc4_platform_drm_remove(struct platform_device *pdev)
> +static void vc4_platform_drm_remove(struct platform_device *pdev)
>  {
> component_master_del(>dev, _drm_ops);
> -
> -   return 0;
>  }
>
>  static const struct of_device_id vc4_of_match[] = {
> @@ -456,7 +454,7 @@ MODULE_DEVICE_TABLE(of, vc4_of_match);
>
>  static struct platform_driver vc4_platform_driver = {
> .probe  = vc4_platform_drm_probe,
> -   .remove = vc4_platform_drm_remove,
> +   .remove_new = vc4_platform_drm_remove,
> .driver = {
> .name   = "vc4-drm",
> .of_match_table = vc4_of_match,
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index a5c075f802e4..839d7d682842 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -1830,20 +1830,18 @@ static int vc4_dsi_dev_probe(struct platform_device 
> *pdev)
> return 0;
>  }
>
> -static int vc4_dsi_dev_remove(struct platform_device *pdev)
> +static void vc4_dsi_dev_remove(struct platform_device *pdev)
>  {
> struct device *dev = >dev;
> struct vc4_dsi *dsi = dev_get_drvdata(dev);
>
> mipi_dsi_host_unregister(>dsi_host);
> vc4_dsi_put(dsi);
> -
> -   return 0;
>  }
>
>  struct platform_driver vc4_dsi_driver = {
>   

Re: [PATCH v2 2/3] DRM: Create new Content Protection connector property

2023-04-24 Thread Dave Stevenson
Hi Mark (and Dmitry)

On Fri, 21 Apr 2023 at 18:07, Dmitry Baryshkov
 wrote:
>
> On 21/04/2023 19:27, Mark Yacoub wrote:
> > From: Mark Yacoub 
>
> Nit: is there a reason for this header? My first impression is that it
> matches your outgoing name & email address and as such is not necessary.
>
> Nit#2: subject should mention 'Key', as you are creating a property for
> the key.
>
> >
> > [Why]
> > To enable Protected Content, some drivers require a key to be injected
> > from user space to enable HDCP on the connector.
> >
> > [How]
> > Create new "Content Protection Property" of type "Blob"
>
> Generic observation is that the ability to inject HDCP keys manually
> seems to be quite unique to your hardware. As such, I think the debugfs
> or sysfs suits better in comparison to the DRM property.

I was about to reply to v1 with a very similar comment over the
requirement to keep HDCP keys secret.

v2 has added WRITE_ONLY blobs so at least another process can't just
read the blob back out again, but it feels like there are still
numerous ways to grab those keys. For an unsecured userspace to have
the keys in the first place seems like a bad move, and IMHO they
should only be held in either a secure environment, or only held in
hardware (passed direct from OTP to HDCP block).


There's also the DRM uAPI requirement for having reviewed patches for
an open source project to go alongside any uAPI change. Do such
patches exist? 
https://docs.kernel.org/gpu/drm-uapi.html#open-source-userspace-requirements

  Dave

> >
> > Signed-off-by: Mark Yacoub 
> > ---
> >   drivers/gpu/drm/drm_atomic_uapi.c | 9 +
> >   include/drm/drm_connector.h   | 6 ++
> >   include/drm/drm_mode_config.h | 6 ++
> >   3 files changed, 21 insertions(+)
> >
> > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c 
> > b/drivers/gpu/drm/drm_atomic_uapi.c
> > index d867e7f9f2cd5..e20bc57cdb05c 100644
> > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > @@ -749,6 +749,11 @@ static int drm_atomic_connector_set_property(struct 
> > drm_connector *connector,
> >   state->content_protection = val;
> >   } else if (property == config->hdcp_content_type_property) {
> >   state->hdcp_content_type = val;
> > + } else if (property == config->content_protection_key_property) {
> > + ret = drm_atomic_replace_property_blob_from_id(
> > + dev, >content_protection_key, val, -1, -1,
> > + );
> > + return ret;
> >   } else if (property == connector->colorspace_property) {
> >   state->colorspace = val;
> >   } else if (property == config->writeback_fb_id_property) {
> > @@ -843,6 +848,10 @@ drm_atomic_connector_get_property(struct drm_connector 
> > *connector,
> >   *val = state->content_protection;
> >   } else if (property == config->hdcp_content_type_property) {
> >   *val = state->hdcp_content_type;
> > + } else if (property == config->content_protection_key_property) {
> > + *val = state->content_protection_key ?
> > +state->content_protection_key->base.id :
> > +0;
> >   } else if (property == config->writeback_fb_id_property) {
> >   /* Writeback framebuffer is one-shot, write and forget */
> >   *val = 0;
> > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > index 7b5048516185c..2fbe51272bfeb 100644
> > --- a/include/drm/drm_connector.h
> > +++ b/include/drm/drm_connector.h
> > @@ -896,6 +896,12 @@ struct drm_connector_state {
> >*/
> >   unsigned int content_protection;
> >
> > + /**
> > +  * @content_protection_key: DRM blob property for holding the Content
> > +  * Protection Key injected from user space.
> > +  */
> > + struct drm_property_blob *content_protection_key;
> > +
> >   /**
> >* @colorspace: State variable for Connector property to request
> >* colorspace change on Sink. This is most commonly used to switch
> > diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h
> > index e5b053001d22e..615d1e5f57562 100644
> > --- a/include/drm/drm_mode_config.h
> > +++ b/include/drm/drm_mode_config.h
> > @@ -887,6 +887,12 @@ struct drm_mode_config {
> >*/
> >   struct drm_property *hdcp_content_type_property;
> >
> > + /**
> > +  * @content_protection_key_property: DRM blob property that receives 
> > the
> > +  * content protection key from user space to be injected into the 
> > kernel.
> > +  */
> > + struct drm_property *content_protection_key_property;
> > +
> >   /* dumb ioctl parameters */
> >   uint32_t preferred_depth, prefer_shadow;
> >
>
> --
> With best wishes
> Dmitry
>


Re: [PATCH v7 10/12] drm/bridge: Implement enable_next_first to alter bridge init order

2023-03-30 Thread Dave Stevenson
Hi Jagan

On Thu, 30 Mar 2023 at 07:56, Jagan Teki  wrote:
>
> On Wed, Mar 29, 2023 at 10:16 PM Maxime Ripard  wrote:
> >
> > On Wed, Mar 29, 2023 at 05:28:28PM +0100, Dave Stevenson wrote:
> > > On Wed, 29 Mar 2023 at 14:19, Jagan Teki  
> > > wrote:
> > > >
> > > > DSI sink devices typically send the MIPI-DCS commands to the DSI host
> > > > via general MIPI_DSI_DCS read and write API.
> > > >
> > > > The classical DSI sequence mentioned that the DSI host receives MIPI-DCS
> > > > commands from the DSI sink first in order to switch HS mode properly.
> > > > Once the DSI host switches to HS mode any MIPI-DCS commands from the
> > > > DSI sink are unfunctional.
> > >
> > > That statement contradicts the spec.
> > > The DSI spec section 8.11.1 Transmission Packet Sequences says that
> > > during any BLLP (Blanking or Low Power) period the host can do any of:
> > > - remain in LP-11
> > > - transmit one or more non-video packets from host to peripheral in 
> > > escape mode
> > > - transmit one or more non-video packets from host to peripheral in
> > > using HS mode
> > > - receive one or more packets from peripheral to host using escape mode
> > > - transmit data on a different virtual channel.
> > >
> > > Indeed if the sink doesn't set MIPI_DSI_MODE_LPM /
> > > MIPI_DSI_MSG_USE_LPM, then the expectation is that any data transfer
> > > will be in HS mode.
> > >
> > > That makes me confused as to the need for this patch.
> >
> > Yeah, and it looks like that would break the expectation that, in
> > enable, a bridge can expect its controller to be in HS mode.
> >
> > I think that was Jagan is trying to do is to work around an issue with
> > the Allwinner DSI driver:
> > https://elixir.bootlin.com/linux/v6.3-rc4/source/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#L775
>
> Correct and I can see it seems to be a classic DSI sequence observed
> in dw-mipi-dsi as well - based on Neil's comments.
> https://lore.kernel.org/all/9aa3d19d-4378-aaf3-6857-c40be5d25...@baylibre.com/

Neil's comments are from 2021, and his response would appear to be
with regard the PHY power up sequence issues that
pre_enable_prev_first should solve. The DSI host pre_enable can now be
called before the sink's pre_enable, therefore allowing the PHY to be
configured in pre_enable. Hacking the PHY init into mode_set is
therefore not required.

I don't see any restriction in dw-mipi-dsi over when transfer can be
called (as long as it is between pre_enable and post_disable), and it
supports MIPI_DSI_MSG_USE_LPM for requesting the command be sent in
either LP or HS mode.

> In fact, I did follow and initialize the command-mode mode_set which
> set low-speed DCS and switch back to video-mode @enable and switch to
> HS but could see the same issue as the host cannot accept DCS as
> before (I might implement improper sequence, but not sure due to lack
> of documentation). But this sequence has issues with calling
> post_disable twice even on dw-mipi-dsi.

Calling up/down the bridge chain from within other bridge elements is
going to have issues and shouldn't be necessary.

The comment in dw-mipi-dsi post_disable[1]
* TODO Only way found to call panel-bridge post_disable &
* panel unprepare before the dsi "final" disable...
* This needs to be fixed in the drm_bridge framework and the API
* needs to be updated to manage our own call chains...

It has now been fixed up with pre_enable_prev_first.

I seem to recall seeing a patchset for one of the DSI hosts (other
than vc4) that was moving the init from mode_set to pre_enable - I
think it is probably [2] for msm.

Cheers
  Dave

[1] 
https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c#L862-L867
[2] 
https://github.com/torvalds/linux/commit/ec7981e6c614254937b37ce0af9eac09901c05c5

> May be Neill, can comment here?
>
> Thanks,
> Jagan.


Re: [PATCH v7 10/12] drm/bridge: Implement enable_next_first to alter bridge init order

2023-03-29 Thread Dave Stevenson
Hi Maxime

On Wed, 29 Mar 2023 at 17:46, Maxime Ripard  wrote:
>
> On Wed, Mar 29, 2023 at 05:28:28PM +0100, Dave Stevenson wrote:
> > On Wed, 29 Mar 2023 at 14:19, Jagan Teki  wrote:
> > >
> > > DSI sink devices typically send the MIPI-DCS commands to the DSI host
> > > via general MIPI_DSI_DCS read and write API.
> > >
> > > The classical DSI sequence mentioned that the DSI host receives MIPI-DCS
> > > commands from the DSI sink first in order to switch HS mode properly.
> > > Once the DSI host switches to HS mode any MIPI-DCS commands from the
> > > DSI sink are unfunctional.
> >
> > That statement contradicts the spec.
> > The DSI spec section 8.11.1 Transmission Packet Sequences says that
> > during any BLLP (Blanking or Low Power) period the host can do any of:
> > - remain in LP-11
> > - transmit one or more non-video packets from host to peripheral in escape 
> > mode
> > - transmit one or more non-video packets from host to peripheral in
> > using HS mode
> > - receive one or more packets from peripheral to host using escape mode
> > - transmit data on a different virtual channel.
> >
> > Indeed if the sink doesn't set MIPI_DSI_MODE_LPM /
> > MIPI_DSI_MSG_USE_LPM, then the expectation is that any data transfer
> > will be in HS mode.
> >
> > That makes me confused as to the need for this patch.
>
> Yeah, and it looks like that would break the expectation that, in
> enable, a bridge can expect its controller to be in HS mode.
>
> I think that was Jagan is trying to do is to work around an issue with
> the Allwinner DSI driver:
> https://elixir.bootlin.com/linux/v6.3-rc4/source/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#L775
>
> This is working mostly fine since we only have panel support and can
> control that, but with bridge support added in the latest patch, then it
> probably doesn't work anymore.
>
> The proper way to fix this isn't to put more logic into the framework,
> it's to make the DSI driver behave as expected by KMS.
>
> Unfortunately, that controller is not documented, so it's not clear to
> me how we can fix it.
>
> IIRC, it's basically a state machine where you would encode the
> transitions between one DSI state and the next depending on what your
> expectations are.
>
> I think there's two problem with the driver that need to be addressed:
>
>   - First the driver will drop back to LP11 mode to submit commands. I
> don't think it's needed and could even be hurtful to the video
> stream if it was to happen during HS mode:
> 
> https://elixir.bootlin.com/linux/v6.3-rc4/source/drivers/gpu/drm/sun4i/sun6i_mipi_dsi.c#L877
>
>   - And then, it looks like, in HSD mode, we never get to go to the
> state LPTX is in (LPDT). It would be interesting to test whether
> adding a transition to that state makes it work or not.

Ooh, not fun.
I'll agree with your assessment - it looks like sunxi driver has
significant limitations on the modes of operation it supports. If
there is no information on sending HS commands, I wonder if it's
possible to note the video state in transfer and stop video, send the
command, and resume video again. Ugly as heck, but possibly the only
real option without documentation. It does raise the question of do
other blocks (eg crtc) need to be stopped as well, or does stopping
the PHY and/or DSI block stop the pixel data getting clocked out.

I can only guess at the meaning of the enum sun6i_dsi_start_inst and
enum sun6i_dsi_inst_id states. LPTX and LPRX are largely obvious, but
HSC(ommand) and HSD(ata) perhaps?
I thought on initial reading that the setup in sun6i_dsi_start made
sense as a sequence of commands, but looking closer at the bitmasking
and shifting I'm not so convinced. Are the DSI_INST_ID_xxx defines
shifts or the bitmask values to or in, as they get used for both.

  Dave


Re: [PATCH v7 10/12] drm/bridge: Implement enable_next_first to alter bridge init order

2023-03-29 Thread Dave Stevenson
Hi Jagan

On Wed, 29 Mar 2023 at 14:19, Jagan Teki  wrote:
>
> DSI sink devices typically send the MIPI-DCS commands to the DSI host
> via general MIPI_DSI_DCS read and write API.
>
> The classical DSI sequence mentioned that the DSI host receives MIPI-DCS
> commands from the DSI sink first in order to switch HS mode properly.
> Once the DSI host switches to HS mode any MIPI-DCS commands from the
> DSI sink are unfunctional.

That statement contradicts the spec.
The DSI spec section 8.11.1 Transmission Packet Sequences says that
during any BLLP (Blanking or Low Power) period the host can do any of:
- remain in LP-11
- transmit one or more non-video packets from host to peripheral in escape mode
- transmit one or more non-video packets from host to peripheral in
using HS mode
- receive one or more packets from peripheral to host using escape mode
- transmit data on a different virtual channel.

Indeed if the sink doesn't set MIPI_DSI_MODE_LPM /
MIPI_DSI_MSG_USE_LPM, then the expectation is that any data transfer
will be in HS mode.

That makes me confused as to the need for this patch.

  Dave

> DSI sink uses the @enable function to send the MIPI-DCS commands. In a
> typical DSI host, sink pipeline the @enable call chain start with the
> DSI host, and then the DSI sink which is the "wrong" order as DSI host
> @enable is called and switched to HS mode before DSI sink @enable.
>
> If the DSI host enables with the @enable_next_first flag then the
> @enable for the DSI sink will be called first before the @enable of
> the DSI host. This alter bridge init order makes sure that the MIPI-DCS
> commands send first and then switch to the HS mode properly by DSI host.
>
> This new flag @enable_next_first that any bridg can set to swap the
> order of @enable (and #disable) for that and the immediately next bridge.
>
> [enable]
> If a bridge sets @enable_next_first, then the @enable for the next bridge
> will be called first before enable of this bridge.
>
> [disable]
> If a bridge sets @enable_next_first, then the @disable for the next bridge
> will be called first before @disable of this bridge to reverse the @enable
> calling direction.
>
> eg:
> - Panel
> - Bridge 1
> - Bridge 2 enable_next_first
> - Bridge 3
> - Bridge 4 enable_next_first
> - Bridge 5 enable_next_first
> - Bridge 6
> - Encoder
>
> Would result in enable's being called as Encoder, Bridge 6, Bridge 3,
> Bridge 4, Bridge 5, Bridge 1, Bridge 2, Panel.
>
> and the result in disable's being called as Panel, Bridge 2, Bridge 1,
> Bridge 5, Bridge 4, Bridge 3, Bridge 6, Encoder.
>
> Signed-off-by: Jagan Teki 
> ---
> Changes for v7:
> - new patch
>
>  drivers/gpu/drm/drm_bridge.c | 171 ++-
>  include/drm/drm_bridge.h |   8 ++
>  2 files changed, 154 insertions(+), 25 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index caf0f341e524..cdc2669b3512 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -577,6 +577,24 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
>  }
>  EXPORT_SYMBOL(drm_bridge_chain_mode_set);
>
> +static void drm_atomic_bridge_call_disable(struct drm_bridge *bridge,
> +  struct drm_atomic_state *old_state)
> +{
> +   if (old_state && bridge->funcs->atomic_disable) {
> +   struct drm_bridge_state *old_bridge_state;
> +
> +   old_bridge_state =
> +   drm_atomic_get_old_bridge_state(old_state,
> +   bridge);
> +   if (WARN_ON(!old_bridge_state))
> +   return;
> +
> +   bridge->funcs->atomic_disable(bridge, old_bridge_state);
> +   } else if (bridge->funcs->disable) {
> +   bridge->funcs->disable(bridge);
> +   }
> +}
> +
>  /**
>   * drm_atomic_bridge_chain_disable - disables all bridges in the encoder 
> chain
>   * @bridge: bridge control structure
> @@ -587,33 +605,73 @@ EXPORT_SYMBOL(drm_bridge_chain_mode_set);
>   * starting from the last bridge to the first. These are called before 
> calling
>   * _encoder_helper_funcs.atomic_disable
>   *
> + * If a bridge sets @enable_next_first, then the @disable for the next bridge
> + * will be called first before @disable of this bridge to reverse the @enable
> + * calling direction.
> + *
> + * Example:
> + * Bridge A ---> Bridge B ---> Bridge C ---> Bridge D ---> Bridge E
> + *
> + * With enable_next_first flag enable in Bridge A, C, D then the resulting
> + * @disable order would be,
> + * Bridge C, Bridge D, Bridge E, Bridge A, Bridge B.
> + *
>   * Note: the bridge passed should be the one closest to the encoder
>   */
>  void drm_atomic_bridge_chain_disable(struct drm_bridge *bridge,
>  struct drm_atomic_state *old_state)
>  {
> struct drm_encoder *encoder;
> -   struct drm_bridge *iter;
> +   struct drm_bridge 

Re: [regression] RPI4B drm vc4: no crtc or sizes since 5.17 (works in 5.16; and still broken in at least 6.1)

2023-03-10 Thread Dave Stevenson
On Fri, 10 Mar 2023 at 12:59, AL13N  wrote:
>
>
> I donno if this is related or not, but since 6.1 has v3d, i'm assuming
> the opengl compositor will be faster and not draw too much cpu?
>
> I did try youtube video, but that on 1080p fullscreen, takes all the CPU
> and seems to have dropped frames still?

Does your browser actually use sensible EGL calls to pass dmabufs
around the system? Chromium with Ozone sort of does, but that's about
it.
It's another thing that is implemented in Raspberry Pi OS.

> does rpi4B actually have video decoding hardware?

I've already referred you to https://github.com/lategoodbye/rpi-zero/issues/43
> VCHIQ codecs - Unknown

It is present in our vendor kernel, but not upstreamed. You've chosen
to run mainline.

> and is this related to
> drm? because netflix did not work at all, which requires drm, but is
> this a different a different drm than this driver?

Digital Rights Management != Direct Rendering Manager.

Netflix on an unsecured platform will only work through something like
Widevine for software decode.

  Dave


Re: [regression] RPI4B drm vc4: no crtc or sizes since 5.17 (works in 5.16; and still broken in at least 6.1)

2023-03-10 Thread Dave Stevenson
On Fri, 10 Mar 2023 at 09:10, AL13N  wrote:
>
> Dave Stevenson schreef op 2023-03-09 13:59:
> > On Wed, 8 Mar 2023 at 22:46, AL13N  wrote:
> >>
> >> AL13N schreef op 2023-03-08 22:16:
> >> > Maxime Ripard schreef op 2023-03-08 13:35:
> >> >> Hi,
> >> >>
> >> >> On Tue, Mar 07, 2023 at 05:10:16PM +, Dave Stevenson wrote:
> >> >>> On Tue, 7 Mar 2023 at 16:25, AL13N  wrote:
> >> >>> > AL13N schreef op 2023-03-06 17:34:
> >> >>> > > I have a RPI4B connected on 2nd HDMI port (furthest away from 
> >> >>> > > power)
> >> >>> > > to a 4K TV, which works until 5.16, from 5.17 there is no X (or
> >> >>> > > plymouth), the cause of no X is that EDID gives nothing, and in the
> >> >>> > > journal; there is "Cannot find any crct or sizes". Only the kernel 
> >> >>> > > is
> >> >>> > > changed for this.
> >> >>> > >

> >>
> >> a bit puzzling why it does EDID block twice and it's twice checksum
> >> invalid?
> >> I also see forcing connector on.
> >>
> >> earlier, i did try to make an edid file from a modeline that worked on
> >> 5.16 and pass it using drm_kms_helper.edid_firmware= ; but that didn't
> >> work, there only was some kind of warning that i should use something
> >> else...
> >
> > It always helps to actually quote warnings or errors.
> > Almost certainly "drm_kms_helper.edid_firmware is deprecated, please
> > use drm.edid_firmware instead.", in which case do as it tells you and
> > use "drm.edid_firmware=".
>
> oh, i interpreted this as "it works for now, but will be removed later"
> ? are you saying it really doesn't work and i should retest with
> "drm.edid_firmware=" ?

Reporting that you got a warning or error message which you then
ignored doesn't help the debug process.
Seeing it's been deprecated since 5.4 in 2017, it would be a fair
candidate to disappear.

> >> reading through all your messages, does this mean, that i should be
> >> able
> >> to boot if we were to "fix" this edid file? and pass it? or is this
> >> something that needs change in kernel?
> >
> > At present you have 2 issues
> > - the monitor or cable doesn't handle the hotplug line correctly
> > - the monitor doesn't provide a valid EDID.
> >
> > The first you can workaround with "video=HDMI-A-2:D".
>
> I thought the video= had to be turned off for drm.edid_firmware= to work
> well?

No - they do 2 different jobs.
video=HDMI-A-2:D will force the connector to report connected, and
therefore trigger a read of the EDID.
drm.edid_firmware means that the EDID used will be read from that file
rather than over the DDC link.

> rpi4 config.txt has a disable_fw_kms_setup=1 that disables the video
> tags that are auto-added to cmdline (this option is commented atm)
> there is also a hdmi_force_hotplug=1 option that is turned on atm

hdmi_force_hotplug=1 only affects the firmware, not the vc4 kernel driver.

> > The second you can work around by capturing the EDID, fixing it, and
> > then using "drm.edid_firmware=".
> > The first fix is to just fixup the checksum (edid-decode even tells
> > you the correct value as 0xEB). That doesn't solve the fact that the
> > EDID contains other rubbish like being an analog display which may
> > cause further issues. The simplest fix for reporting as an analog
> > display is to change byte 20 from 0x00 to 0x80, and then correct the
> > checksum again.
> >
> > The EDID advertises 4k60, 1080p60, and GTF 2288x1432 @ 61Hz.
> > In order to support 4k60 it needs to support HDMI2.0 and enabling
> > scrambling via SCDC. That should also be signalled in the EDID Sink
> > Capability Data Structure block but isn't, so 4k60 support may be
> > compromised.
>
> the rpi4 also has in config.txt a hdmi_enable_4kp60=1, which i have not
> turned on atm; i don't know if that has any impact here...

Without that then any mode that requires a pixel clock above the
340MHz limit of HDMI 1.4 will be filtered out. 4k60 will therefore not
be available to you on your system.

> > Sorry, all of this comes back to the monitor vendor shipping rubbish.
> > None of this is the fault of the vc4 driver, and it only worked under
> > 5.16 by chance.
>
> do the config.txt directives on the rpi4 have any impact here? I always
> figured these options only changed the cmdline video= parameters, it
> can't really have an

Re: [regression] RPI4B drm vc4: no crtc or sizes since 5.17 (works in 5.16; and still broken in at least 6.1)

2023-03-09 Thread Dave Stevenson
On Wed, 8 Mar 2023 at 22:46, AL13N  wrote:
>
> AL13N schreef op 2023-03-08 22:16:
> > Maxime Ripard schreef op 2023-03-08 13:35:
> >> Hi,
> >>
> >> On Tue, Mar 07, 2023 at 05:10:16PM +, Dave Stevenson wrote:
> >>> On Tue, 7 Mar 2023 at 16:25, AL13N  wrote:
> >>> > AL13N schreef op 2023-03-06 17:34:
> >>> > > I have a RPI4B connected on 2nd HDMI port (furthest away from power)
> >>> > > to a 4K TV, which works until 5.16, from 5.17 there is no X (or
> >>> > > plymouth), the cause of no X is that EDID gives nothing, and in the
> >>> > > journal; there is "Cannot find any crct or sizes". Only the kernel is
> >>> > > changed for this.
> >>> > >
> >>> > > In 5.16 instead of this message there is a bunch of hex lines prefixed
> >>> > > with BAD.
> >>> > >
> >>> > > It is still broken in 6.1 at the very least.
> >>> > >
> >>> > > I donno if this is related to this part, but I wanted to try a newer
> >>> > > kernel, because the RPI4 seems to do all the video decoding in
> >>> > > software and cannot seem to handle it.
> >>> > >
> >>> > >
> >>> > > logs:
> >>> > > vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> >>> > > vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> >>> > > vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > > vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > > vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > > vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > > vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > > checking generic (3ea81000 12c000) vs hw (0 )
> >>> > > fb0: switching to vc4 from simple
> >>> > > Console: switching to colour dummy device 80x25
> >>> > > [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> >>> > > vc4-drm gpu: [drm] Cannot find any crtc or sizes
> >>> >
> >>> > 5.16 log has:
> >>> >
> >>> > vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> >>> > vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> >>> > vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> >>> > [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> >>> > [00] BAD  00 ff ff ff ff ff ff 00 36 74 00 00 00 00 00 00
> >>> > [00] BAD  0b 1f 01 03 00 23 01 78 0a cf 74 a3 57 4c b0 23
> >>> > [00] BAD  09 48 4c 00 00 00 01 01 01 ff 01 ff ff 01 01 01
> >>> > [00] BAD  01 01 01 01 01 20 08 e8 00 30 f2 70 5a 80 b0 58
> >>> > [00] BAD  8a 00 c4 8e 21 00 00 1e 02 3a 80 18 71 38 2d 40
> >>> > [00] BAD  58 2c 45 00 c4 8e 21 00 00 1e 00 00 00 fc 00 53
> >>> > [00] BAD  41 4c 4f 52 41 0a 20 20 20 20 20 20 00 00 00 fd
> >>> > [00] BAD  00 3b 46 1f 8c 3c 00 0a 20 20 20 20 20 20 01 aa
> >>> > Console: switching to colour frame buffer device 240x67
> >>> > vc4-drm gpu: [drm] fb0: vc4drmfb frame buffer device
> >>> >
> >>> >
> >>> > i donno what this bad is, but it doesn't happen in 5.17... maybe these
> >>> > BAD got filtered out, but they did end up working for me? or something?
> >>> > i donno...
> >>>
> >>> Run it through edid-decode - the checksum is wrong.
> >>>
> >>> Block 0, Base EDID:
> >>>   EDID Structure Version & Revision: 1.3
> >>>   Vendor & Product Identification:
> >>> Manufacturer: MST
> >>> Model: 0
> >>> Made in: week 11 of 2021
> >>>   Basic Display Parameters & Features:
> >>> Analog display
> >>> Input voltage level: 0.7/0.3 V
> >>> Blank level equals black level
> >>> Maximum image size: 35 cm x 

Re: [regression] RPI4B drm vc4: no crtc or sizes since 5.17 (works in 5.16; and still broken in at least 6.1)

2023-03-09 Thread Dave Stevenson
On Thu, 9 Mar 2023 at 11:26, AL13N  wrote:
>
> Dave Stevenson schreef op 2023-03-07 18:10:
> > Hi Maarten
> >
> > On Tue, 7 Mar 2023 at 16:25, AL13N  wrote:
> >>
> >> AL13N schreef op 2023-03-06 17:34:
> >> > Hi,
> >> >
> >> > I have a RPI4B connected on 2nd HDMI port (furthest away from power)
> >> > to a 4K TV, which works until 5.16, from 5.17 there is no X (or
> >> > plymouth), the cause of no X is that EDID gives nothing, and in the
> >> > journal; there is "Cannot find any crct or sizes". Only the kernel is
> >> > changed for this.
> >> >
> >> > In 5.16 instead of this message there is a bunch of hex lines prefixed
> >> > with BAD.
> >> >
> >> > It is still broken in 6.1 at the very least.
> >> >
> >> > I donno if this is related to this part, but I wanted to try a newer
> >> > kernel, because the RPI4 seems to do all the video decoding in
> >> > software and cannot seem to handle it.
> >> >
> >> >
> >> > logs:
> >> > vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> >> > vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> >> > vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> > vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> > vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> > vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> > vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> > checking generic (3ea81000 12c000) vs hw (0 )
> >> > fb0: switching to vc4 from simple
> >> > Console: switching to colour dummy device 80x25
> >> > [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> >> > vc4-drm gpu: [drm] Cannot find any crtc or sizes
> >>
> >> 5.16 log has:
> >>
> >> vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> >> vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> >> vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> >> [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> >> [00] BAD  00 ff ff ff ff ff ff 00 36 74 00 00 00 00 00 00
> >> [00] BAD  0b 1f 01 03 00 23 01 78 0a cf 74 a3 57 4c b0 23
> >> [00] BAD  09 48 4c 00 00 00 01 01 01 ff 01 ff ff 01 01 01
> >> [00] BAD  01 01 01 01 01 20 08 e8 00 30 f2 70 5a 80 b0 58
> >> [00] BAD  8a 00 c4 8e 21 00 00 1e 02 3a 80 18 71 38 2d 40
> >> [00] BAD  58 2c 45 00 c4 8e 21 00 00 1e 00 00 00 fc 00 53
> >> [00] BAD  41 4c 4f 52 41 0a 20 20 20 20 20 20 00 00 00 fd
> >> [00] BAD  00 3b 46 1f 8c 3c 00 0a 20 20 20 20 20 20 01 aa
> >> Console: switching to colour frame buffer device 240x67
> >> vc4-drm gpu: [drm] fb0: vc4drmfb frame buffer device
> >>
> >>
> >> i donno what this bad is, but it doesn't happen in 5.17... maybe these
> >> BAD got filtered out, but they did end up working for me? or
> >> something?
> >> i donno...
> >
> > Run it through edid-decode - the checksum is wrong.
> >
> > Block 0, Base EDID:
> >   EDID Structure Version & Revision: 1.3
> >   Vendor & Product Identification:
> > Manufacturer: MST
> > Model: 0
> > Made in: week 11 of 2021
> >   Basic Display Parameters & Features:
> > Analog display
> > Input voltage level: 0.7/0.3 V
> > Blank level equals black level
> > Maximum image size: 35 cm x 1 cm
> > Gamma: 2.20
> > RGB color display
> > First detailed timing is the preferred timing
> >   Color Characteristics:
> > Red  : 0.6396, 0.3398
> > Green: 0.2998, 0.6904
> > Blue : 0.1376, 0.0380
> > White: 0.2822, 0.2968
> >   Established Timings I & II: none
> >   Standard Timings:
> > GTF :  2288x1432   61.000 Hz  16:10   90.463 kHz 282.245 MHz
> >   Detailed Timing Descriptors:
> > DTD 1:  3840x2160   60.000 Hz  16:9   135.000 kHz 594.000 MHz (708
> > mm x 398 mm)
> >  Hfront  176 Hsync  88 Hback 296 Hpol P
&

Re: [regression] RPI4B drm vc4: no crtc or sizes since 5.17 (works in 5.16; and still broken in at least 6.1)

2023-03-07 Thread Dave Stevenson
Hi Maarten

On Tue, 7 Mar 2023 at 16:25, AL13N  wrote:
>
> AL13N schreef op 2023-03-06 17:34:
> > Hi,
> >
> > I have a RPI4B connected on 2nd HDMI port (furthest away from power)
> > to a 4K TV, which works until 5.16, from 5.17 there is no X (or
> > plymouth), the cause of no X is that EDID gives nothing, and in the
> > journal; there is "Cannot find any crct or sizes". Only the kernel is
> > changed for this.
> >
> > In 5.16 instead of this message there is a bunch of hex lines prefixed
> > with BAD.
> >
> > It is still broken in 6.1 at the very least.
> >
> > I donno if this is related to this part, but I wanted to try a newer
> > kernel, because the RPI4 seems to do all the video decoding in
> > software and cannot seem to handle it.
> >
> >
> > logs:
> > vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> > vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> > vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> > vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> > vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> > vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> > vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> > checking generic (3ea81000 12c000) vs hw (0 )
> > fb0: switching to vc4 from simple
> > Console: switching to colour dummy device 80x25
> > [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> > vc4-drm gpu: [drm] Cannot find any crtc or sizes
>
> 5.16 log has:
>
> vc4-drm gpu: bound fef05700.hdmi (ops vc4_hdmi_ops [vc4])
> vc4-drm gpu: bound fe004000.txp (ops vc4_txp_ops [vc4])
> vc4-drm gpu: bound fe206000.pixelvalve (ops vc4_crtc_ops [vc4])
> vc4-drm gpu: bound fe207000.pixelvalve (ops vc4_crtc_ops [vc4])
> vc4-drm gpu: bound fe20a000.pixelvalve (ops vc4_crtc_ops [vc4])
> vc4-drm gpu: bound fe216000.pixelvalve (ops vc4_crtc_ops [vc4])
> vc4-drm gpu: bound fec12000.pixelvalve (ops vc4_crtc_ops [vc4])
> [drm] Initialized vc4 0.0.0 20140616 for gpu on minor 0
> [00] BAD  00 ff ff ff ff ff ff 00 36 74 00 00 00 00 00 00
> [00] BAD  0b 1f 01 03 00 23 01 78 0a cf 74 a3 57 4c b0 23
> [00] BAD  09 48 4c 00 00 00 01 01 01 ff 01 ff ff 01 01 01
> [00] BAD  01 01 01 01 01 20 08 e8 00 30 f2 70 5a 80 b0 58
> [00] BAD  8a 00 c4 8e 21 00 00 1e 02 3a 80 18 71 38 2d 40
> [00] BAD  58 2c 45 00 c4 8e 21 00 00 1e 00 00 00 fc 00 53
> [00] BAD  41 4c 4f 52 41 0a 20 20 20 20 20 20 00 00 00 fd
> [00] BAD  00 3b 46 1f 8c 3c 00 0a 20 20 20 20 20 20 01 aa
> Console: switching to colour frame buffer device 240x67
> vc4-drm gpu: [drm] fb0: vc4drmfb frame buffer device
>
>
> i donno what this bad is, but it doesn't happen in 5.17... maybe these
> BAD got filtered out, but they did end up working for me? or something?
> i donno...

Run it through edid-decode - the checksum is wrong.

Block 0, Base EDID:
  EDID Structure Version & Revision: 1.3
  Vendor & Product Identification:
Manufacturer: MST
Model: 0
Made in: week 11 of 2021
  Basic Display Parameters & Features:
Analog display
Input voltage level: 0.7/0.3 V
Blank level equals black level
Maximum image size: 35 cm x 1 cm
Gamma: 2.20
RGB color display
First detailed timing is the preferred timing
  Color Characteristics:
Red  : 0.6396, 0.3398
Green: 0.2998, 0.6904
Blue : 0.1376, 0.0380
White: 0.2822, 0.2968
  Established Timings I & II: none
  Standard Timings:
GTF :  2288x1432   61.000 Hz  16:10   90.463 kHz 282.245 MHz
  Detailed Timing Descriptors:
DTD 1:  3840x2160   60.000 Hz  16:9   135.000 kHz 594.000 MHz (708
mm x 398 mm)
 Hfront  176 Hsync  88 Hback 296 Hpol P
 Vfront8 Vsync  10 Vback  72 Vpol P
DTD 2:  1920x1080   60.000 Hz  16:967.500 kHz 148.500 MHz (708
mm x 398 mm)
 Hfront   88 Hsync  44 Hback 148 Hpol P
 Vfront4 Vsync   5 Vback  36 Vpol P
Display Product Name: 'SALORA'
  Display Range Limits:
Monitor ranges (GTF): 59-70 Hz V, 31-140 kHz H, max dotclock 600 MHz
  Extension blocks: 1
Checksum: 0xaa (should be 0xeb)

Weird that it also says that it's an analog display when it's
connected over HDMI. Something rather bizarre there, and I think it'll
hit problems in drm_edid at [1] as we end up with a connector having
no color_formats defined. I was discussing this with Maxime only last
week, but in relation to VGA monitors connected through HDMI to VGA
adapters without rewriting the EDID.


If you have an issue between 5.16 and 5.17, then I'd guess at [2] and
your monitor not asserting hotplug correctly. The raw hotplug status
is reported in /sys/kernel/debug/dri/N/hdmi0_regs (N will be either 0
or 1 depending on the probe order of the vc4 and v3d drivers). Grep
for HDMI_HOTPLUG.

Incorrect hotplug behaviour causes grief when combined with HDMI2.0
and scrambling. If you don' t know the other end has been
disconnected, then you 

Re: [PATCH] drm: document TV margin properties

2023-02-28 Thread Dave Stevenson
On Tue, 28 Feb 2023 at 11:45, Ville Syrjälä
 wrote:
>
> On Tue, Feb 28, 2023 at 11:37:38AM +, Dave Stevenson wrote:
> > Hi Pekka
> >
> > On Tue, 28 Feb 2023 at 10:12, Pekka Paalanen  wrote:
> > >
> > > On Tue, 28 Feb 2023 09:53:47 +
> > > Simon Ser  wrote:
> > >
> > > > On Tuesday, February 28th, 2023 at 09:46, Pekka Paalanen 
> > > >  wrote:
> > > >
> > > > > can these be negative as well, to achieve overscan and not just
> > > > > underscan? Did I get overscan and underscan right... these are related
> > > > > to under/overscan, aren't they?
> > > > >
> > > > > Hmm, no, I guess that doesn't make sense, there is no room in the
> > > > > signal to have negative margins, it would result in clipping the
> > > > > framebuffer while scaling up. So this can only be used to scale
> > > > > framebuffer down, add borders, and the TV then scales it back up
> > > > > again?
> > > >
> > > > Correct.
> > > >
> > > > > Looks like neither my Intel nor AMD cards support these, I don't see
> > > > > the properties. More things to the list of KMS properties Weston needs
> > > > > to explicitly control. Oh, it seems vc4 exclusive for now.
> >
> > I've started a discussion with Simon with regard overscan handling [1].
> > There would be nothing stopping Weston ignoring the DRM properties if
> > Weston/userspace provides a way to reduce the destintation rectangle
> > on the display device. Using that would also be renderer agnostic.
> >
> > [1] https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3597
> >
> > > > i915 does support it but for TV connectors only 
> > > > (i915/display/intel_tv.c).
> > > > gud also supports it.
> > > >
> > > > > Where does this text appear in the HTML kernel docs? I tried to look 
> > > > > at
> > > > > drm_connector.c but I cannot find the spot where this patch applies.
> > > >
> > > > Here:
> > > > https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#analog-tv-specific-connector-properties
> > >
> > > Analog TV properties? So this does not apply to e.g. HDMI?
> > >
> > > I believe HDMI TVs do have the problems that margins could mitigate.
> >
> > Correct. Particularly on TVs instead of monitors, it's not uncommon to
> > find the HDMI output gets overscanned.
> >
> > > > > Is this actually a connector property? How does that work, should this
> > > > > not be a CRTC property?
> > > >
> > > > Yeah, it's a connector property for some reason.
> > > >
> > > > > Is this instead not scaling anything but simply sending metadata
> > > > > through the connector?
> > > >
> > > > No metadata is sent. This is purely equivalent to setting up CRTC_*
> > > > properties to scale the planes.
> > >
> > > Oh! That would be really good to mention in the doc. Maybe even prefer
> > > plane props over this? Or is this for analog TV, and plane props for
> > > digital TV?
> > >
> > >
> > > The above are the important comments. All below is just musings you can
> > > ignore if you wish.
> > >
> > > > > Or are there underlying requirements that this connector property is
> > > > > actually affecting the CRTC, which means that it is fundamentally
> > > > > impossible to use multiple connectors with different values on the 
> > > > > same
> > > > > CRTC? And drivers will reject any attempt, so there is no need to
> > > > > define what conflicting settings will do?
> > > >
> > > > I don't think any driver above supports cloning CRTCs for these
> > > > connector types. i915 sets clonable = false for these connectors.
> > > > vc4 picks the first connector's TV margins, always.
> > >
> > > Sounds like i915 does it right, and vc4 does not, assuming vc4 does not
> > > prevent cloning.
> >
> > The cloneable flag is in struct intel_encoder, not core.
>
> It gets converted into the core thing by intel_encoder_possible_clones().

Thanks Ville.
vc4 never adds additional possible_clones, therefore I believe it is
still doing the right thing.

  Dave


Re: [PATCH] drm: document TV margin properties

2023-02-28 Thread Dave Stevenson
Hi Pekka

On Tue, 28 Feb 2023 at 10:12, Pekka Paalanen  wrote:
>
> On Tue, 28 Feb 2023 09:53:47 +
> Simon Ser  wrote:
>
> > On Tuesday, February 28th, 2023 at 09:46, Pekka Paalanen 
> >  wrote:
> >
> > > can these be negative as well, to achieve overscan and not just
> > > underscan? Did I get overscan and underscan right... these are related
> > > to under/overscan, aren't they?
> > >
> > > Hmm, no, I guess that doesn't make sense, there is no room in the
> > > signal to have negative margins, it would result in clipping the
> > > framebuffer while scaling up. So this can only be used to scale
> > > framebuffer down, add borders, and the TV then scales it back up
> > > again?
> >
> > Correct.
> >
> > > Looks like neither my Intel nor AMD cards support these, I don't see
> > > the properties. More things to the list of KMS properties Weston needs
> > > to explicitly control. Oh, it seems vc4 exclusive for now.

I've started a discussion with Simon with regard overscan handling [1].
There would be nothing stopping Weston ignoring the DRM properties if
Weston/userspace provides a way to reduce the destintation rectangle
on the display device. Using that would also be renderer agnostic.

[1] https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3597

> > i915 does support it but for TV connectors only (i915/display/intel_tv.c).
> > gud also supports it.
> >
> > > Where does this text appear in the HTML kernel docs? I tried to look at
> > > drm_connector.c but I cannot find the spot where this patch applies.
> >
> > Here:
> > https://dri.freedesktop.org/docs/drm/gpu/drm-kms.html#analog-tv-specific-connector-properties
>
> Analog TV properties? So this does not apply to e.g. HDMI?
>
> I believe HDMI TVs do have the problems that margins could mitigate.

Correct. Particularly on TVs instead of monitors, it's not uncommon to
find the HDMI output gets overscanned.

> > > Is this actually a connector property? How does that work, should this
> > > not be a CRTC property?
> >
> > Yeah, it's a connector property for some reason.
> >
> > > Is this instead not scaling anything but simply sending metadata
> > > through the connector?
> >
> > No metadata is sent. This is purely equivalent to setting up CRTC_*
> > properties to scale the planes.
>
> Oh! That would be really good to mention in the doc. Maybe even prefer
> plane props over this? Or is this for analog TV, and plane props for
> digital TV?
>
>
> The above are the important comments. All below is just musings you can
> ignore if you wish.
>
> > > Or are there underlying requirements that this connector property is
> > > actually affecting the CRTC, which means that it is fundamentally
> > > impossible to use multiple connectors with different values on the same
> > > CRTC? And drivers will reject any attempt, so there is no need to
> > > define what conflicting settings will do?
> >
> > I don't think any driver above supports cloning CRTCs for these
> > connector types. i915 sets clonable = false for these connectors.
> > vc4 picks the first connector's TV margins, always.
>
> Sounds like i915 does it right, and vc4 does not, assuming vc4 does not
> prevent cloning.

The cloneable flag is in struct intel_encoder, not core.

vc4 doesn't support cloning of a single CRTC to multiple connectors at
all, and I believe sets up the possible_crtc bitmasks correctly to
denote that.

  Dave

> >
> > > IOW, does simply the existence of these properties on a connector
> > > guarantee that the connector must be the only one on a CRTC?
> >
> > I suppose that there could exist some hardware capable of applying
> > margins post-CRTC? Such driver could support cloning CRTCs and still
> > applying the connector margins correctly.
>
> Yeah, theoretically. But in the KMS object model, is there the idea
> that connectors do not do image manipulation, they can only convert the
> signal type at most and send metadata?
>
>
> Thanks,
> pq


Re: [PATCH] drm: document TV margin properties

2023-02-27 Thread Dave Stevenson
On Mon, 27 Feb 2023 at 12:21, Simon Ser  wrote:
>
> Add docs for "{left,right,top,bottom} margin" properties.
>
> Signed-off-by: Simon Ser 
> Cc: Maxime Ripard 
> Cc: Daniel Vetter 
> Cc: Pekka Paalanen 
> Cc: Noralf Trønnes 
> Cc: Mateusz Kwiatkowski 

This certainly matches my understanding of the properties. Thanks.

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/drm_connector.c | 14 ++
>  1 file changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> index 9d0250c28e9b..65a586680940 100644
> --- a/drivers/gpu/drm/drm_connector.c
> +++ b/drivers/gpu/drm/drm_connector.c
> @@ -1590,10 +1590,6 @@ 
> EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
>
>  /*
>   * TODO: Document the properties:
> - *   - left margin
> - *   - right margin
> - *   - top margin
> - *   - bottom margin
>   *   - brightness
>   *   - contrast
>   *   - flicker reduction
> @@ -1651,6 +1647,16 @@ 
> EXPORT_SYMBOL(drm_connector_attach_dp_subconnector_property);
>   *
>   * Drivers can set up this property by calling
>   * drm_mode_create_tv_properties().
> + *
> + * left margin, right margin, top margin, bottom margin:
> + * Add margins to the connector's viewport.
> + *
> + * The value is the size in pixels of the black border which will be
> + * added. The attached CRTC's content will be scaled to fill the whole
> + * area inside the margin.
> + *
> + * Drivers can set up these properties by calling
> + * drm_mode_create_tv_margin_properties().
>   */
>
>  /**
> --
> 2.39.2
>
>


Re: [PATCH 1/2] drm: document DRM_IOCTL_PRIME_HANDLE_TO_FD and PRIME_FD_TO_HANDLE

2023-02-20 Thread Dave Stevenson
On Mon, 20 Feb 2023 at 15:57, Simon Ser  wrote:
>
> On Monday, February 20th, 2023 at 16:49, Dave Stevenson 
>  wrote:
>
> > > + * User-space sets _prime_handle.fd with a DMA-BUF file descriptor to
> > > + * import, and gets back a GEM handle in _prime_handle.handle.
> > > + * _prime_handle.flags is unused.
> >
> > Is it worth explicitly stating that the handle would be released via
> > DRM_IOCTL_GEM_CLOSE? I've had userspace developers query how to
> > release imported handles in the past.
>
> v2 spells this out I think.

It does - thanks.
I was reading back through my emails from Friday and the weekend, and
hadn't noticed v2 :-/ Sorry for the noise.

  Dave


Re: [PATCH 1/2] drm: document DRM_IOCTL_PRIME_HANDLE_TO_FD and PRIME_FD_TO_HANDLE

2023-02-20 Thread Dave Stevenson
Hi Simon

On Thu, 16 Feb 2023 at 13:09, Simon Ser  wrote:
>
> Signed-off-by: Simon Ser 
> Cc: Daniel Vetter 
> Cc: Pekka Paalanen 
> Cc: Daniel Stone 
> ---
>  include/uapi/drm/drm.h | 17 +
>  1 file changed, 17 insertions(+)
>
> diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
> index 4cb956a52aee..54b2313c8332 100644
> --- a/include/uapi/drm/drm.h
> +++ b/include/uapi/drm/drm.h
> @@ -1012,7 +1012,24 @@ extern "C" {
>  #define DRM_IOCTL_UNLOCK   DRM_IOW( 0x2b, struct drm_lock)
>  #define DRM_IOCTL_FINISH   DRM_IOW( 0x2c, struct drm_lock)
>
> +/**
> + * DRM_IOCTL_PRIME_HANDLE_TO_FD - Convert a GEM handle to a DMA-BUF FD.
> + *
> + * User-space sets _prime_handle.handle with the GEM handle to export and
> + * _prime_handle.flags, and gets back a DMA-BUF file descriptor in
> + * _prime_handle.fd.
> + */
>  #define DRM_IOCTL_PRIME_HANDLE_TO_FDDRM_IOWR(0x2d, struct 
> drm_prime_handle)
> +/**
> + * DRM_IOCTL_PRIME_FD_TO_HANDLE - Convert a DMA-BUF FD to a GEM handle.
> + *
> + * User-space sets _prime_handle.fd with a DMA-BUF file descriptor to
> + * import, and gets back a GEM handle in _prime_handle.handle.
> + * _prime_handle.flags is unused.

Is it worth explicitly stating that the handle would be released via
DRM_IOCTL_GEM_CLOSE? I've had userspace developers query how to
release imported handles in the past.

  Dave

> + *
> + * If an existing GEM handle refers to the memory object backing the DMA-BUF,
> + * that GEM handle is returned.
> + */
>  #define DRM_IOCTL_PRIME_FD_TO_HANDLEDRM_IOWR(0x2e, struct 
> drm_prime_handle)
>
>  #define DRM_IOCTL_AGP_ACQUIRE  DRM_IO(  0x30)
> --
> 2.39.1
>
>


Re: [PATCH v2 3/9] drm/vc4: hdmi: Add Broadcast RGB property to allow override of RGB range

2023-02-20 Thread Dave Stevenson
Hi Hans

On Sat, 18 Feb 2023 at 11:33, Hans Verkuil  wrote:
>
> Hi Maxime, Dave,
>
> On 26/01/2023 14:46, Maxime Ripard wrote:
> > From: Dave Stevenson 
> >
> > Copy Intel's "Broadcast RGB" property semantics to add manual override
> > of the HDMI pixel range for monitors that don't abide by the content
> > of the AVI Infoframe.
>
> Do we have to copy that property as-is?

Firstly I'll agree with your later comment that having this control
allows testing of a range of output modes, and working around HDMI
sinks that have dodgy implementations.
(In our vendor kernel we now also have a property to override the
kernel chosen output format to enable testing of YCbCr4:4:4 and 4:2:2
output).

The DRM subsystem has the requirement for an open-source userspace
project to be using any new property before it will be merged [1].
This property already exists for i915 and gma-500, therefore avoids
that requirement.

There are objections to the UAPI for Broadcast RGB [2], but if it's
good enough for the existing implementations then there can be no
objection to it being implemented in the same way for other drivers.
Otherwise it is a missing feature of the DRM API, and the linked
discussion is realistically at least a year away from being resolved.
Why bury our heads in the sand for that period?

[1] 
https://dri.freedesktop.org/docs/drm/gpu/drm-uapi.html#open-source-userspace-requirements
[2] https://lists.freedesktop.org/archives/dri-devel/2023-February/391061.html

> First of all, I think this should really be a drm-level property, rather than
> a driver property: RGB Quantization Range mismatches are the bane of my life,
> and I think a way to override this would help everyone.

Linked to above, if it were the preferred method for controlling this
then I would expect it to become a drm-level property.

> Secondly, I hate the name they came up with: 'Broadcast RGB' is pretty 
> meaningless.
> Can't we stick to something closer to what the CTA-861/HDMI specs use, which 
> is
> 'RGB Quantization Range'? So either use that, or just 'RGB Range'.
>
> In addition, 'Limited 16:235' should just be 'Limited' since the actual range
> depends on the bits-per-color-component.

It's documented UAPI with those names[3], therefore any change would
be a change to user-space's expectation and a regression. At least by
sticking with the same names then any user space implementation that
exists for i915 or gma-500 will also work in the same way on vc4.

[3] 
https://www.kernel.org/doc/html/latest/gpu/drm-kms.html#existing-kms-properties

> >
> > Signed-off-by: Dave Stevenson 
> > Signed-off-by: Maxime Ripard 
> > ---
> >  drivers/gpu/drm/vc4/vc4_hdmi.c | 97 
> > --
> >  drivers/gpu/drm/vc4/vc4_hdmi.h |  9 
> >  2 files changed, 102 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> > index 4b3bf77bb5cd..78749c6fa837 100644
> > --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> > @@ -150,10 +150,16 @@ static bool vc4_hdmi_mode_needs_scrambling(const 
> > struct drm_display_mode *mode,
> >  }
> >
> >  static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi,
> > -const struct drm_display_mode *mode)
> > +struct vc4_hdmi_connector_state 
> > *vc4_state)
> >  {
> > + const struct drm_display_mode *mode = _hdmi->saved_adjusted_mode;
> >   struct drm_display_info *display = _hdmi->connector.display_info;
> >
> > + if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_LIMITED)
> > + return false;
> > + else if (vc4_state->broadcast_rgb == VC4_HDMI_BROADCAST_RGB_FULL)
> > + return true;
> > +
> >   return !display->is_hdmi ||
> >   drm_default_rgb_quant_range(mode) == 
> > HDMI_QUANTIZATION_RANGE_FULL;
> >  }
> > @@ -524,8 +530,12 @@ static int vc4_hdmi_connector_atomic_check(struct 
> > drm_connector *connector,
> >  {
> >   struct drm_connector_state *old_state =
> >   drm_atomic_get_old_connector_state(state, connector);
> > + struct vc4_hdmi_connector_state *old_vc4_state =
> > + conn_state_to_vc4_hdmi_conn_state(old_state);
> >   struct drm_connector_state *new_state =
> >   drm_atomic_get_new_connector_state(state, connector);
> > + struct vc4_hdmi_connector_state *new_vc4_state =
> > + conn_state_to_vc4_hdmi_conn_state(new_state);
> >   struct drm_crtc *crtc = new_state->crtc;
> >
> >   if (!crtc)
&g

Re: [RFT PATCH v2 1/3] drm/bridge: tc358762: Set pre_enable_prev_first

2023-02-01 Thread Dave Stevenson
On Tue, 31 Jan 2023 at 22:22, Douglas Anderson  wrote:
>
> Set the "pre_enable_prev_first" as provided by commit 4fb912e5e190
> ("drm/bridge: Introduce pre_enable_prev_first to alter bridge init
> order"). This should allow us to revert commit ec7981e6c614
> ("drm/msm/dsi: don't powerup at modeset time for parade-ps8640") and
> commit 7d8e9a90509f ("drm/msm/dsi: move DSI host powerup to modeset
> time").

I see no reference in the TC358762 datasheet to requiring the DSI
interface to be in any particular state.
However, setting this flag does mean that the DSI host doesn't need to
power up and down for each host_transfer request from
tc358762_pre_enable/tc358762_init, so on that basis I'm good with it.

Reviewed-by: Dave Stevenson 

> Cc: Dave Stevenson 
> Cc: Dmitry Baryshkov 
> Cc: Abhinav Kumar 
> Signed-off-by: Douglas Anderson 
> ---
>
> (no changes since v1)
>
>  drivers/gpu/drm/bridge/tc358762.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/bridge/tc358762.c 
> b/drivers/gpu/drm/bridge/tc358762.c
> index 0b6a28436885..77f7f7f54757 100644
> --- a/drivers/gpu/drm/bridge/tc358762.c
> +++ b/drivers/gpu/drm/bridge/tc358762.c
> @@ -229,6 +229,7 @@ static int tc358762_probe(struct mipi_dsi_device *dsi)
> ctx->bridge.funcs = _bridge_funcs;
> ctx->bridge.type = DRM_MODE_CONNECTOR_DPI;
> ctx->bridge.of_node = dev->of_node;
> +   ctx->bridge.pre_enable_prev_first = true;
>
> drm_bridge_add(>bridge);
>
> --
> 2.39.1.456.gfc5497dd1b-goog
>


Re: [PATCH v11 3/3] drm: exynos: dsi: Restore proper bridge chain order

2023-01-20 Thread Dave Stevenson
Hi Jagan

On Fri, 20 Jan 2023 at 19:10, Jagan Teki  wrote:
>
> Hi Dave,
>
> On Sat, Jan 21, 2023 at 12:26 AM Dave Stevenson
>  wrote:
> >
> > Hi Jagan
> >
> > Responding due to Marek's comment on the "Add Samsung MIPI DSIM
> > bridge" series, although I know very little about the Exynos
> > specifics, and may well be missing context of what you're trying to
> > achieve.
> >
> > On Mon, 12 Dec 2022 at 18:29, Jagan Teki  wrote:
> > >
> > > Restore the proper bridge chain by finding the previous bridge
> > > in the chain instead of passing NULL.
> > >
> > > This establishes a proper bridge chain while attaching downstream
> > > bridges.
> > >
> > > Reviewed-by: Marek Vasut 
> > > Signed-off-by: Marek Szyprowski 
> > > Signed-off-by: Jagan Teki 
> > > ---
> > > Changes for v11:
> > > - add bridge.pre_enable_prev_first
> > > Changes for v10:
> > > - collect Marek review tag
> > >
> > >  drivers/gpu/drm/exynos/exynos_drm_dsi.c | 9 +++--
> > >  1 file changed, 7 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c 
> > > b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > > index ec673223d6b7..9d10a89d28f1 100644
> > > --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > > +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> > > @@ -1428,7 +1428,8 @@ static int exynos_dsi_attach(struct drm_bridge 
> > > *bridge,
> > >  {
> > > struct exynos_dsi *dsi = bridge_to_dsi(bridge);
> > >
> > > -   return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, 
> > > flags);
> > > +   return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
> > > +flags);
> >
> > Agreed on this change.
> >
> > >  }
> > >
> > >  static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
> > > @@ -1474,7 +1475,10 @@ static int exynos_dsi_host_attach(struct 
> > > mipi_dsi_host *host,
> > >
> > > drm_bridge_add(>bridge);
> > >
> > > -   drm_bridge_attach(encoder, >bridge, NULL, 0);
> > > +   drm_bridge_attach(encoder, >bridge,
> > > + list_first_entry_or_null(>bridge_chain,
> > > +  struct drm_bridge,
> > > +  chain_node), 0);
> >
> > What bridge are you expecting between the encoder and this bridge?
> > The encoder is the drm_simple_encoder_init encoder that you've created
> > in exynos_dsi_bind, so separating that from the bridge you're also
> > creating here seems weird.
> >
> > >
> > > /*
> > >  * This is a temporary solution and should be made by more 
> > > generic way.
> > > @@ -1709,6 +1713,7 @@ static int exynos_dsi_probe(struct platform_device 
> > > *pdev)
> > > dsi->bridge.funcs = _dsi_bridge_funcs;
> > > dsi->bridge.of_node = dev->of_node;
> > > dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
> > > +   dsi->bridge.pre_enable_prev_first = true;
> >
> > Setting dsi->bridge.pre_enable_prev_first on what is presumably the
> > DSI host controller seems a little odd.
> > Same question again - what bridge are you expecting to be upstream of
> > the DSI host that needs to be preenabled before it? Whilst it's
> > possible that there's another bridge, I'd have expected that to be the
> > first link from your encoder as they appear to both belong to the same
> > bit of driver.
>
> Let me answer all together here. I can explain a bit about one of the
> pipelines used in Exynos. Exynos DSI DRM drivers have some strict host
> initialization which is not the same as what we used in i.MX8M even
> though it uses the same DSIM IP.
>
> Exynos5433 Decon -> Exynos MIC -> Exynos DSI -> s6e3ha2 DSI panel
>
> Here MIC is the bridge, Exynos DSI is the bridge and the requirement
> is to expect the upstream bridge to pre_enable first from DSI which
> means the MIC.

That makes sense for the pre_enable_prev_first flag.

The drm_bridge_attach(... list_first_entry_or_null) still seems a
little weird. I think you are making the assumption that there is only
ever going to be the zero or one bridge (the MIC) between encoder and
DSI bridge - the DSI bridge is linking itself to the first entry off
the encoder bridge_chain (or NULL to link to the encoder). Is that
reasonable? I've no idea!

I must confess to not having looked at the attaching sequence
recently, and I'm about to head home for the weekend.
I have no real knowledge of how Exynos is working, and am aware that
you're having to rejuggle stuff to try and support i.MX8M and Exynos,
so leave that one up to you.

Cheers
  Dave


Re: [PATCH v10 00/18] drm: Add Samsung MIPI DSIM bridge

2023-01-20 Thread Dave Stevenson
Hi Marek & Jagan

On Fri, 20 Jan 2023 at 15:06, Marek Vasut  wrote:
>
> On 1/20/23 15:41, Jagan Teki wrote:
> > Hi Fabio,
>
> Hello all,
>
> > On Fri, Jan 20, 2023 at 5:36 PM Fabio Estevam  wrote:
> >>
> >> Hi Jagan,
> >>
> >> On Thu, Jan 19, 2023 at 2:59 PM Jagan Teki  
> >> wrote:
> >>
> >>> There are two patch series prior to this need to apply.
> >>>
> >>> https://patchwork.kernel.org/project/dri-devel/patch/20221212145745.15387-1-ja...@amarulasolutions.com/
> >>> https://patchwork.kernel.org/project/dri-devel/cover/20221212182923.29155-1-ja...@amarulasolutions.com/
> >>
> >> Would it make sense to re-submit these two patches as part of your series?
> >
> > The previous version's comment was to separate them from the DSIM series.
>
> Hm, seems like those first two patches got stuck. I fixed up the
> malformed Fixes: line (it was split across two lines and had angular
> brackets around it) and picked the first series via drm-misc-next .
>
> Can you send a subsequent patch to convert the DSIM_* macros to BIT()
> macro , since checkpatch --strict complains about it ?
>
> For the second series, you likely want a RB from Maxime Ripard and Dave
> Stevenson first about the probe order handling.

Not sure what I can add for "Enable prepare_prev_first flag for
samsung-s6e panels" and "tc358764: Enable pre_enable_prev_first flag"
as I have no datasheet for those devices.
On the basis that they are wanting the DSI host to be in LP-11 before
prepare/pre_enable, then setting the flag is the right thing. More
than happy to say
Acked-by: Dave Stevenson 
to those two (I can't find them quickly in my mail to respond directly).

I have just sent a separate response on the third patch.

  Dave


Re: [PATCH v11 3/3] drm: exynos: dsi: Restore proper bridge chain order

2023-01-20 Thread Dave Stevenson
Hi Jagan

Responding due to Marek's comment on the "Add Samsung MIPI DSIM
bridge" series, although I know very little about the Exynos
specifics, and may well be missing context of what you're trying to
achieve.

On Mon, 12 Dec 2022 at 18:29, Jagan Teki  wrote:
>
> Restore the proper bridge chain by finding the previous bridge
> in the chain instead of passing NULL.
>
> This establishes a proper bridge chain while attaching downstream
> bridges.
>
> Reviewed-by: Marek Vasut 
> Signed-off-by: Marek Szyprowski 
> Signed-off-by: Jagan Teki 
> ---
> Changes for v11:
> - add bridge.pre_enable_prev_first
> Changes for v10:
> - collect Marek review tag
>
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c | 9 +++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c 
> b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index ec673223d6b7..9d10a89d28f1 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1428,7 +1428,8 @@ static int exynos_dsi_attach(struct drm_bridge *bridge,
>  {
> struct exynos_dsi *dsi = bridge_to_dsi(bridge);
>
> -   return drm_bridge_attach(bridge->encoder, dsi->out_bridge, NULL, 
> flags);
> +   return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
> +flags);

Agreed on this change.

>  }
>
>  static const struct drm_bridge_funcs exynos_dsi_bridge_funcs = {
> @@ -1474,7 +1475,10 @@ static int exynos_dsi_host_attach(struct mipi_dsi_host 
> *host,
>
> drm_bridge_add(>bridge);
>
> -   drm_bridge_attach(encoder, >bridge, NULL, 0);
> +   drm_bridge_attach(encoder, >bridge,
> + list_first_entry_or_null(>bridge_chain,
> +  struct drm_bridge,
> +  chain_node), 0);

What bridge are you expecting between the encoder and this bridge?
The encoder is the drm_simple_encoder_init encoder that you've created
in exynos_dsi_bind, so separating that from the bridge you're also
creating here seems weird.

>
> /*
>  * This is a temporary solution and should be made by more generic 
> way.
> @@ -1709,6 +1713,7 @@ static int exynos_dsi_probe(struct platform_device 
> *pdev)
> dsi->bridge.funcs = _dsi_bridge_funcs;
> dsi->bridge.of_node = dev->of_node;
> dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
> +   dsi->bridge.pre_enable_prev_first = true;

Setting dsi->bridge.pre_enable_prev_first on what is presumably the
DSI host controller seems a little odd.
Same question again - what bridge are you expecting to be upstream of
the DSI host that needs to be preenabled before it? Whilst it's
possible that there's another bridge, I'd have expected that to be the
first link from your encoder as they appear to both belong to the same
bit of driver.

  Dave

> ret = component_add(dev, _dsi_component_ops);
> if (ret)
> --
> 2.25.1
>


Re: [PATCH] drm/panel: boe-tv101wum-nl6: Ensure DSI writes succeed during disable

2023-01-16 Thread Dave Stevenson
Hi Stephen

On Fri, 13 Jan 2023 at 21:12, Stephen Boyd  wrote:
>
> Quoting Dave Stevenson (2023-01-13 08:27:29)
> > Hi Stephen
> >
> > On Fri, 6 Jan 2023 at 03:01, Stephen Boyd  wrote:
> > >
> > > The unprepare sequence has started to fail after moving to panel bridge
> > > code in the msm drm driver (commit 007ac0262b0d ("drm/msm/dsi: switch to
> > > DRM_PANEL_BRIDGE")). You'll see messages like this in the kernel logs:
> > >
> > >panel-boe-tv101wum-nl6 ae94000.dsi.0: failed to set panel off: -22
> > >
> > > This is because boe_panel_enter_sleep_mode() needs an operating DSI link
> > > to set the panel into sleep mode. Performing those writes in the
> > > unprepare phase of bridge ops is too late, because the link has already
> > > been torn down by the DSI controller in post_disable, i.e. the PHY has
> > > been disabled, etc. See dsi_mgr_bridge_post_disable() for more details
> > > on the DSI .
> > >
> > > Split the unprepare function into a disable part and an unprepare part.
> > > For now, just the DSI writes to enter sleep mode are put in the disable
> > > function. This fixes the panel off routine and keeps the panel happy.
> >
> > It is documented that the mipi_dsi_host_ops transfer function should
> > be called with the host in any state [1], so the host driver is
> > failing there.
>
> Thanks for the info! It says "Drivers that need the underlying device to
> be powered to perform these operations will first need to make sure it’s
> been properly enabled." Does that mean the panel driver needs to make
> sure the underlying dsi host device is powered? The sentence is too
> ambiguous for me to understand what 'drivers' and 'underlying device'
> are.

The DSI host driver (ie in your case something under
drivers/gpu/drm/msm/dsi) should ensure that a transfer can be made,
regardless of state.

I must say that this has been documented as the case, but doesn't
necessarily reflect reality in a number of drivers.

> >
> > This sounds like the same issue I was addressing in adding the
> > prepare_prev_first flag to drm_panel, and pre_enable_prev_first to
> > drm_bridge via [2].
> > Defining prepare_prev_first for your panel would result in the host
> > pre_enable being called before the panel prepare, and therefore the
> > transfer calls from boe_panel_init_dcs_cmd boe_panel_prepare won't be
> > relying on the DSI host powering up early. It will also call the panel
> > unprepare before the DSI host bridge post_disable is called, and
> > therefore the DSI host will still be powered up and the transfer won't
> > fail.
> >
> > Actually I've just noted the comment at [3]. [2] is that framework fix
> > that means that the magic workaround isn't required, but it will
> > require this panel to opt in to the ordering change.
>
> Cool. Glad that we can clean that up with your series.
>
> Is it wrong to split unprepare to a disable and unprepare phase? I'm not
> super keen on fixing 6.1 stable kernels by opting this driver into the
> ordering change. Splitting the phase into two is small and simple and
> works. I suspect changing the ordering may uncover more bugs, or be a
> larger task. I'd be glad to test that series[2] from you to get rid of
> [3].

Ah, I hadn't realised it was a regression in a released kernel :(

Splitting into a disable and unprepare is totally fine. Normally
disable would normally disable the panel and backlight (probably by
drm_panel before the panel disable call), with unprepare disabling
power and clocks

Do note that AIUI you will be telling the panel to enter sleep mode
whilst video is still being transmitted. That should be safe as the
panel has to still be partially active to handle an exit sleep mode
command, but actually powering hardware down at that point could cause
DSI bus arbitration errors as clock or data lanes could be pulled down
when the host is trying to adopt HS or LP11.

  Dave

> >
> >
> > [1] 
> > https://www.kernel.org/doc/html/latest/gpu/drm-kms-helpers.html#c.mipi_dsi_host_ops
> > [2] https://patchwork.freedesktop.org/series/100252/
> > [3] 
> > https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/msm/dsi/dsi_manager.c#L47
> >


Re: [PATCH] drm/panel: boe-tv101wum-nl6: Ensure DSI writes succeed during disable

2023-01-13 Thread Dave Stevenson
Hi Stephen

On Fri, 6 Jan 2023 at 03:01, Stephen Boyd  wrote:
>
> The unprepare sequence has started to fail after moving to panel bridge
> code in the msm drm driver (commit 007ac0262b0d ("drm/msm/dsi: switch to
> DRM_PANEL_BRIDGE")). You'll see messages like this in the kernel logs:
>
>panel-boe-tv101wum-nl6 ae94000.dsi.0: failed to set panel off: -22
>
> This is because boe_panel_enter_sleep_mode() needs an operating DSI link
> to set the panel into sleep mode. Performing those writes in the
> unprepare phase of bridge ops is too late, because the link has already
> been torn down by the DSI controller in post_disable, i.e. the PHY has
> been disabled, etc. See dsi_mgr_bridge_post_disable() for more details
> on the DSI .
>
> Split the unprepare function into a disable part and an unprepare part.
> For now, just the DSI writes to enter sleep mode are put in the disable
> function. This fixes the panel off routine and keeps the panel happy.

It is documented that the mipi_dsi_host_ops transfer function should
be called with the host in any state [1], so the host driver is
failing there.

This sounds like the same issue I was addressing in adding the
prepare_prev_first flag to drm_panel, and pre_enable_prev_first to
drm_bridge via [2].
Defining prepare_prev_first for your panel would result in the host
pre_enable being called before the panel prepare, and therefore the
transfer calls from boe_panel_init_dcs_cmd boe_panel_prepare won't be
relying on the DSI host powering up early. It will also call the panel
unprepare before the DSI host bridge post_disable is called, and
therefore the DSI host will still be powered up and the transfer won't
fail.

Actually I've just noted the comment at [3]. [2] is that framework fix
that means that the magic workaround isn't required, but it will
require this panel to opt in to the ordering change.

Cheers.
  Dave

[1] 
https://www.kernel.org/doc/html/latest/gpu/drm-kms-helpers.html#c.mipi_dsi_host_ops
[2] https://patchwork.freedesktop.org/series/100252/
[3] 
https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/msm/dsi/dsi_manager.c#L47

> My Wormdingler has an integrated touchscreen that stops responding to
> touch if the panel is only half disabled too. This patch fixes it. And
> finally, this saves power when the screen is off because without this
> fix the regulators for the panel are left enabled when nothing is being
> displayed on the screen.
>
> Fixes: 007ac0262b0d ("drm/msm/dsi: switch to DRM_PANEL_BRIDGE")
> Fixes: a869b9db7adf ("drm/panel: support for boe tv101wum-nl6 wuxga dsi video 
> mode panel")
> Cc: yangcong 
> Cc: Douglas Anderson 
> Cc: Jitao Shi 
> Cc: Sam Ravnborg 
> Cc: Rob Clark 
> Cc: Dmitry Baryshkov 
> Signed-off-by: Stephen Boyd 
> ---
>  drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c | 16 
>  1 file changed, 12 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c 
> b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> index 857a2f0420d7..c924f1124ebc 100644
> --- a/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> +++ b/drivers/gpu/drm/panel/panel-boe-tv101wum-nl6.c
> @@ -1193,14 +1193,11 @@ static int boe_panel_enter_sleep_mode(struct 
> boe_panel *boe)
> return 0;
>  }
>
> -static int boe_panel_unprepare(struct drm_panel *panel)
> +static int boe_panel_disable(struct drm_panel *panel)
>  {
> struct boe_panel *boe = to_boe_panel(panel);
> int ret;
>
> -   if (!boe->prepared)
> -   return 0;
> -
> ret = boe_panel_enter_sleep_mode(boe);
> if (ret < 0) {
> dev_err(panel->dev, "failed to set panel off: %d\n", ret);
> @@ -1209,6 +1206,16 @@ static int boe_panel_unprepare(struct drm_panel *panel)
>
> msleep(150);
>
> +   return 0;
> +}
> +
> +static int boe_panel_unprepare(struct drm_panel *panel)
> +{
> +   struct boe_panel *boe = to_boe_panel(panel);
> +
> +   if (!boe->prepared)
> +   return 0;
> +
> if (boe->desc->discharge_on_disable) {
> regulator_disable(boe->avee);
> regulator_disable(boe->avdd);
> @@ -1528,6 +1535,7 @@ static enum drm_panel_orientation 
> boe_panel_get_orientation(struct drm_panel *pa
>  }
>
>  static const struct drm_panel_funcs boe_panel_funcs = {
> +   .disable = boe_panel_disable,
> .unprepare = boe_panel_unprepare,
> .prepare = boe_panel_prepare,
> .enable = boe_panel_enable,
>
> base-commit: 1b929c02afd37871d5afb9d498426f83432e71c2
> --
> https://chromeos.dev
>


Re: [PATCH 5/9] drm/vc4: hdmi: Rework the CSC matrices organization

2023-01-11 Thread Dave Stevenson
Hi Thomas

Thanks for the review

On Wed, 11 Jan 2023 at 15:03, Thomas Zimmermann  wrote:
>
> Hi
>
> Am 07.12.22 um 17:07 schrieb Maxime Ripard:
> > From: Dave Stevenson 
> >
> > The CSC matrices were stored as separate matrix for each colorspace, and
> > if we wanted a limited or full RGB output.
> >
> > This created some gaps in our support and we would not always pick the
> > relevant matrix.
> >
> > Let's rework our data structure to store one per colorspace, and then a
> > matrix for limited range and one for full range. This makes us add a new
> > matrix to support full range BT709 YUV output, and drops the redundant
> > (but somehow different) BT709 YUV444 vs YUV422 matrix.
>
> The final sentence is confusing and I didn't understand how two
> different matrices can now be just one.

Two changes to accommodate the hardware requirements:

Firstly the driver was only defining
vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709 and
vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709. There was no matrix for
full_rgb_to_full_yuv_bt709, so that had to be added.

Secondly, for some reason when in 444 mode the hardware wants the
matrix rows in a different order. That is why
vc5_hdmi_csc_full_rgb_to_limited_yuv444_bt709 differed from
vc5_hdmi_csc_full_rgb_to_limited_yuv422_bt709 - it was a simple
reordering of the rows.

This patch dropped the special handling for 444, and in the process
programmed the wrong coefficients into the hardware :-(
Patch 6/9 then reintroduces this reordering, so really should be
squashed into the one patch.

Looking at my more recent work, it looks like I messed up on 6/9 too.
One of the patches on [1] corrects that row swapping for yuv444 - I
was obviously having a bad day.

Maxime: Are you OK to fix that up?

Thanks

  Dave

[1] https://github.com/raspberrypi/linux/pull/5249/commits

> Best regards
> Thomas
>
> >
> > Signed-off-by: Dave Stevenson 
> > Signed-off-by: Maxime Ripard 
> > ---
> >   drivers/gpu/drm/vc4/vc4_hdmi.c | 124 
> > +
> >   1 file changed, 63 insertions(+), 61 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> > index 51469939a8b4..299a8fe7a2ae 100644
> > --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> > +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> > @@ -1178,68 +1178,72 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi 
> > *vc4_hdmi,
> >   }
> >
> >   /*
> > - * If we need to output Full Range RGB, then use the unity matrix
> > + * Matrices for (internal) RGB to RGB output.
> >*
> > - * [ 1  0  0  0]
> > - * [ 0  1  0  0]
> > - * [ 0  0  1  0]
> > - *
> > - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
> > - */
> > -static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = {
> > - { 0x2000, 0x, 0x, 0x },
> > - { 0x, 0x2000, 0x, 0x },
> > - { 0x, 0x, 0x2000, 0x },
> > -};
> > -
> > -/*
> > - * CEA VICs other than #1 require limited range RGB output unless
> > - * overridden by an AVI infoframe. Apply a colorspace conversion to
> > - * squash 0-255 down to 16-235. The matrix here is:
> > - *
> > - * [ 0.8594 0  0  16]
> > - * [ 0  0.8594 0  16]
> > - * [ 0  0  0.8594 16]
> > - *
> > - * Matrix is signed 2p13 fixed point, with signed 9p6 offsets
> > + * Matrices are signed 2p13 fixed point, with signed 9p6 offsets
> >*/
> > -static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = {
> > - { 0x1b80, 0x, 0x, 0x0400 },
> > - { 0x, 0x1b80, 0x, 0x0400 },
> > - { 0x, 0x, 0x1b80, 0x0400 },
> > +static const u16 vc5_hdmi_csc_full_rgb_to_rgb[2][3][4] = {
> > + {
> > + /*
> > +  * Full range - unity
> > +  *
> > +  * [ 1  0  0  0]
> > +  * [ 0  1  0  0]
> > +  * [ 0  0  1  0]
> > +  */
> > + { 0x2000, 0x, 0x, 0x },
> > + { 0x, 0x2000, 0x, 0x },
> > + { 0x, 0x, 0x2000, 0x },
> > + },
> > + {
> > + /*
> > +  * Limited range
> > +  *
> > +  * CEA VICs other than #1 require limited range RGB
> > +  * output unless overridden by an AVI infoframe. Apply a
> > +  * colorspace conversion to squash 0-255 down to 16-235.
> > +  * The matrix here is:
> > +  

Re: [PATCH 08/15] drm/vc4: hvs: Ignore atomic_flush if we're disabled

2023-01-09 Thread Dave Stevenson
Hi Maxime

On Wed, 7 Dec 2022 at 11:55, Maxime Ripard  wrote:
>
> atomic_flush will be called for each CRTC even if they aren't enabled.
>
> The whole code we have there will thus run without a properly affected
> channel, which can then result in all sorts of weird behaviour.
>
> Signed-off-by: Maxime Ripard 

Reviewed-by: Dave Stevenson 

> ---
>  drivers/gpu/drm/vc4/vc4_hvs.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
> index 3582ede1a0aa..5fadbf219542 100644
> --- a/drivers/gpu/drm/vc4/vc4_hvs.c
> +++ b/drivers/gpu/drm/vc4/vc4_hvs.c
> @@ -579,6 +579,9 @@ void vc4_hvs_atomic_flush(struct drm_crtc *crtc,
> return;
> }
>
> +   if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
> +   return;
> +
> if (debug_dump_regs) {
> DRM_INFO("CRTC %d HVS before:\n", drm_crtc_index(crtc));
> vc4_hvs_dump_state(hvs);
>
> --
> 2.38.1


[PATCH] drm/bridge: panel: Set pre_enable_prev_first from drmm_panel_bridge_add

2022-12-22 Thread Dave Stevenson
Commit 5ea6b1702781 ("drm/panel: Add prepare_prev_first flag to drm_panel")
added code to copy prepare_prev_first from drm_panel to pre_enable_prev_first
in drm_bridge when called through devm_panel_bridge_add, but
missed drmm_panel_bridge_add.

Add the same code to drmm_panel_bridge_add.

Fixes: 5ea6b1702781 ("drm/panel: Add prepare_prev_first flag to drm_panel")
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/bridge/panel.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 03c3274dc3d9..1708098fba6d 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -404,6 +404,8 @@ struct drm_bridge *drmm_panel_bridge_add(struct drm_device 
*drm,
if (ret)
return ERR_PTR(ret);
 
+   bridge->pre_enable_prev_first = panel->prepare_prev_first;
+
return bridge;
 }
 EXPORT_SYMBOL(drmm_panel_bridge_add);
-- 
2.34.1



[PATCH v4 2/6] drm/mediatek: dp: Replace usage of drm_bridge_chain_ functions

2022-12-05 Thread Dave Stevenson
Commit f70ac097a2cf ("drm/mediatek: Add MT8195 Embedded DisplayPort
driver") added usage of the drm_bridge_chain_ functions which are
to be deprecated.

Replace with the drm_atomic_bridge_chain_ variants using the
current state.

Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/mediatek/mtk_dp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c 
b/drivers/gpu/drm/mediatek/mtk_dp.c
index 9d085c05c49c..b4feaabdb6a7 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -1981,7 +1981,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
struct cea_sad *sads;
 
if (!enabled) {
-   drm_bridge_chain_pre_enable(bridge);
+   drm_atomic_bridge_chain_pre_enable(bridge, 
connector->state->state);
 
/* power on aux */
mtk_dp_update_bits(mtk_dp, MTK_DP_TOP_PWR_STATE,
@@ -2019,7 +2019,7 @@ static struct edid *mtk_dp_get_edid(struct drm_bridge 
*bridge,
   DP_PWR_STATE_BANDGAP_TPLL,
   DP_PWR_STATE_MASK);
 
-   drm_bridge_chain_post_disable(bridge);
+   drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
}
 
return new_edid;
-- 
2.34.1



[PATCH v4 3/6] drm/bridge: Drop unused drm_bridge_chain functions

2022-12-05 Thread Dave Stevenson
From: Sam Ravnborg 

The drm_bridge_chain_{pre_enable,enable,disable,post_disable} has no
users left and we have atomic variants that should be used.
Drop them so they do not gain new users.

Adjust a few comments to avoid references to the dropped functions.

Signed-off-by: Sam Ravnborg 
Reviewed-by: Maxime Ripard 
Reviewed-by: Laurent Pinchart 
Cc: Laurent Pinchart 
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: Andrzej Hajda 
Cc: Neil Armstrong 
Cc: Robert Foss 
Cc: Daniel Vetter 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/drm_bridge.c | 110 ---
 include/drm/drm_bridge.h |  28 -
 2 files changed, 138 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 1545c50fd1c8..bb7fc09267af 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -509,61 +509,6 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
 
-/**
- * drm_bridge_chain_disable - disables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.disable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called before
- * calling the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_disable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-   struct drm_bridge *iter;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_reverse(iter, >bridge_chain, chain_node) {
-   if (iter->funcs->disable)
-   iter->funcs->disable(iter);
-
-   if (iter == bridge)
-   break;
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_disable);
-
-/**
- * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
- *encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.post_disable op for all the bridges in the
- * encoder chain, starting from the first bridge to the last. These are called
- * after completing the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->post_disable)
-   bridge->funcs->post_disable(bridge);
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_post_disable);
-
 /**
  * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
  *encoder chain
@@ -593,61 +538,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_set);
 
-/**
- * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
- *  encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.pre_enable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called
- * before calling the encoder's commit op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-   struct drm_bridge *iter;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_reverse(iter, >bridge_chain, chain_node) {
-   if (iter->funcs->pre_enable)
-   iter->funcs->pre_enable(iter);
-
-   if (iter == bridge)
-   break;
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
-
-/**
- * drm_bridge_chain_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.enable op for all the bridges in the encoder
- * chain, starting from the first bridge to the last. These are called
- * after completing the encoder's commit op.
- *
- * Note that the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_enable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->enable)
-   bridge->funcs->enable(bridge);
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_enable);
-
 /**
  * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
  * @bridge: bridge control structure
diff --git a/include/drm/

[PATCH v4 4/6] drm/bridge: Introduce pre_enable_prev_first to alter bridge init order

2022-12-05 Thread Dave Stevenson
DSI sink devices typically want the DSI host powered up and configured
before they are powered up. pre_enable is the place this would normally
happen, but they are called in reverse order from panel/connector towards
the encoder, which is the "wrong" order.

Add a new flag pre_enable_prev_first that any bridge can set
to swap the order of pre_enable (and post_disable) for that and the
immediately previous bridge.
Should the immediately previous bridge also set the
pre_enable_prev_first flag, the previous bridge to that will be called
before either of those which requested pre_enable_prev_first.

eg:
- Panel
- Bridge 1
- Bridge 2 pre_enable_prev_first
- Bridge 3
- Bridge 4 pre_enable_prev_first
- Bridge 5 pre_enable_prev_first
- Bridge 6
- Encoder
Would result in pre_enable's being called as Panel, Bridge 1, Bridge 3,
Bridge 2, Bridge 6, Bridge 5, Bridge 4, Encoder.

Signed-off-by: Dave Stevenson 
Tested-by: Frieder Schrempf 
Reviewed-by: Frieder Schrempf 
---
 drivers/gpu/drm/drm_bridge.c | 145 +--
 include/drm/drm_bridge.h |   8 ++
 2 files changed, 129 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index bb7fc09267af..5f40c83b1b42 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -581,6 +581,25 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge 
*bridge,
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 
+static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
+   struct drm_atomic_state 
*old_state)
+{
+   if (old_state && bridge->funcs->atomic_post_disable) {
+   struct drm_bridge_state *old_bridge_state;
+
+   old_bridge_state =
+   drm_atomic_get_old_bridge_state(old_state,
+   bridge);
+   if (WARN_ON(!old_bridge_state))
+   return;
+
+   bridge->funcs->atomic_post_disable(bridge,
+  old_bridge_state);
+   } else if (bridge->funcs->post_disable) {
+   bridge->funcs->post_disable(bridge);
+   }
+}
+
 /**
  * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
  *   in the encoder chain
@@ -592,36 +611,86 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
  * starting from the first bridge to the last. These are called after 
completing
  * _encoder_helper_funcs.atomic_disable
  *
+ * If a bridge sets @pre_enable_prev_first, then the @post_disable for that
+ * bridge will be called before the previous one to reverse the @pre_enable
+ * calling direction.
+ *
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
  struct drm_atomic_state *old_state)
 {
struct drm_encoder *encoder;
+   struct drm_bridge *next, *limit;
 
if (!bridge)
return;
 
encoder = bridge->encoder;
+
list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->atomic_post_disable) {
-   struct drm_bridge_state *old_bridge_state;
+   limit = NULL;
+
+   if (!list_is_last(>chain_node, >bridge_chain)) 
{
+   next = list_next_entry(bridge, chain_node);
+
+   if (next->pre_enable_prev_first) {
+   /* next bridge had requested that prev
+* was enabled first, so disabled last
+*/
+   limit = next;
+
+   /* Find the next bridge that has NOT requested
+* prev to be enabled first / disabled last
+*/
+   list_for_each_entry_from(next, 
>bridge_chain,
+chain_node) {
+   if (next->pre_enable_prev_first) {
+   next = list_prev_entry(next, 
chain_node);
+   limit = next;
+   break;
+   }
+   }
+
+   /* Call these bridges in reverse order */
+   list_for_each_entry_from_reverse(next, 
>bridge_chain,
+chain_node) {
+   if (next == bridge)
+   break;
+
+

[PATCH v4 6/6] drm/bridge: Document the expected behaviour of DSI host controllers

2022-12-05 Thread Dave Stevenson
The exact behaviour of DSI host controllers is not specified,
therefore define it.

Signed-off-by: Dave Stevenson 
Reviewed-by: Laurent Pinchart 
---
 Documentation/gpu/drm-kms-helpers.rst |  7 +
 drivers/gpu/drm/drm_bridge.c  | 39 +++
 2 files changed, 46 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index a4860ffd6e86..b8ab05e42dbb 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -188,6 +188,13 @@ Bridge Helper Reference
 .. kernel-doc:: drivers/gpu/drm/drm_bridge.c
:export:
 
+MIPI-DSI bridge operation
+-
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :doc: dsi bridge operations
+
+
 Bridge Connector Helper Reference
 -
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 5f40c83b1b42..c3d69af02e79 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -153,6 +153,45 @@
  * situation when probing.
  */
 
+/**
+ * DOC: dsi bridge operations
+ *
+ * DSI host interfaces are expected to be implemented as bridges rather than
+ * encoders, however there are a few aspects of their operation that need to
+ * be defined in order to provide a consistent interface.
+ *
+ * A DSI host should keep the PHY powered down until the pre_enable operation 
is
+ * called. All lanes are in an undefined idle state up to this point, and it
+ * must not be assumed that it is LP-11.
+ * pre_enable should initialise the PHY, set the data lanes to LP-11, and the
+ * clock lane to either LP-11 or HS depending on the mode_flag
+ * %MIPI_DSI_CLOCK_NON_CONTINUOUS.
+ *
+ * Ordinarily the downstream bridge DSI peripheral pre_enable will have been
+ * called before the DSI host. If the DSI peripheral requires LP-11 and/or
+ * the clock lane to be in HS mode prior to pre_enable, then it can set the
+ * _enable_prev_first flag to request the pre_enable (and
+ * post_disable) order to be altered to enable the DSI host first.
+ *
+ * Either the CRTC being enabled, or the DSI host enable operation should 
switch
+ * the host to actively transmitting video on the data lanes.
+ *
+ * The reverse also applies. The DSI host disable operation or stopping the 
CRTC
+ * should stop transmitting video, and the data lanes should return to the 
LP-11
+ * state. The DSI host _disable operation should disable the PHY.
+ * If the _enable_prev_first flag is set, then the DSI peripheral's
+ * bridge _disable will be called before the DSI host's post_disable.
+ *
+ * Whilst it is valid to call _transfer prior to pre_enable or after
+ * post_disable, the exact state of the lanes is undefined at this point. The
+ * DSI host should initialise the interface, transmit the data, and then 
disable
+ * the interface again.
+ *
+ * Ultra Low Power State (ULPS) is not explicitly supported by DRM. If
+ * implemented, it therefore needs to be handled entirely within the DSI Host
+ * driver.
+ */
+
 static DEFINE_MUTEX(bridge_lock);
 static LIST_HEAD(bridge_list);
 
-- 
2.34.1



[PATCH v4 5/6] drm/panel: Add prepare_prev_first flag to drm_panel

2022-12-05 Thread Dave Stevenson
Mapping to the drm_bridge flag pre_enable_prev_first,
add a new flag prepare_prev_first to drm_panel to allow
the panel driver to request that the upstream bridge should
be pre_enabled before the panel prepare.

Signed-off-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/bridge/panel.c |  2 ++
 include/drm/drm_panel.h| 10 ++
 2 files changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 216af76d0042..03c3274dc3d9 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -364,6 +364,8 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct 
device *dev,
devres_free(ptr);
}
 
+   bridge->pre_enable_prev_first = panel->prepare_prev_first;
+
return bridge;
 }
 EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 994bfcdd84c5..432fab2347eb 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -188,6 +188,16 @@ struct drm_panel {
 * Panel entry in registry.
 */
struct list_head list;
+
+   /**
+* @prepare_prev_first:
+*
+* The previous controller should be prepared first, before the prepare
+* for the panel is called. This is largely required for DSI panels
+* where the DSI host controller should be initialised to LP-11 before
+* the panel is powered up.
+*/
+   bool prepare_prev_first;
 };
 
 void drm_panel_init(struct drm_panel *panel, struct device *dev,
-- 
2.34.1



[PATCH v4 1/6] drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs

2022-12-05 Thread Dave Stevenson
From: Sam Ravnborg 

The atomic variants of enable/disable in drm_bridge_funcs are the
preferred operations - introduce these.

The ps8640 driver used the non-atomic variants of the 
drm_bridge_chain_pre_enable/
drm_bridge_chain_post_disable - convert these to the atomic variants.

v2:
  - Init state operations in drm_bridge_funcs (Laurent)

Signed-off-by: Sam Ravnborg 
Reviewed-by: Maxime Ripard 
Cc: Jitao Shi 
Cc: Philip Chen 
Cc: Neil Armstrong 
Cc: Robert Foss 
Cc: Laurent Pinchart 
Cc: Jonas Karlman 
Cc: Jernej Skrabec 
Reviewed-by: Laurent Pinchart 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/bridge/parade-ps8640.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index f74090a9cc9e..4b361d7d5e44 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -15,6 +15,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -442,7 +443,8 @@ static const struct dev_pm_ops ps8640_pm_ops = {
pm_runtime_force_resume)
 };
 
-static void ps8640_pre_enable(struct drm_bridge *bridge)
+static void ps8640_atomic_pre_enable(struct drm_bridge *bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
@@ -476,7 +478,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge)
ps_bridge->pre_enabled = true;
 }
 
-static void ps8640_post_disable(struct drm_bridge *bridge)
+static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
+  struct drm_bridge_state 
*old_bridge_state)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
 
@@ -554,7 +557,7 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * EDID, for this chip, we need to do a full poweron, otherwise it will
 * fail.
 */
-   drm_bridge_chain_pre_enable(bridge);
+   drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
 
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
@@ -564,7 +567,7 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * before, return the chip to its original power state.
 */
if (poweroff)
-   drm_bridge_chain_post_disable(bridge);
+   drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
 
return edid;
 }
@@ -579,8 +582,11 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = 
{
.attach = ps8640_bridge_attach,
.detach = ps8640_bridge_detach,
.get_edid = ps8640_bridge_get_edid,
-   .post_disable = ps8640_post_disable,
-   .pre_enable = ps8640_pre_enable,
+   .atomic_post_disable = ps8640_atomic_post_disable,
+   .atomic_pre_enable = ps8640_atomic_pre_enable,
+   .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+   .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+   .atomic_reset = drm_atomic_helper_bridge_reset,
 };
 
 static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 
*ps_bridge)
-- 
2.34.1



[PATCH v4 0/6] DSI host and peripheral initialisation ordering

2022-12-05 Thread Dave Stevenson
github.com/6by9/linux/tree/drm-misc-next-vc4_dsi
[8] https://github.com/6by9/linux/tree/rpi-5.15.y-sn65dsi83
My branches are going to be out of date by now - sorry.

Dave Stevenson (4):
  drm/mediatek: dp: Replace usage of drm_bridge_chain_ functions
  drm/bridge: Introduce pre_enable_prev_first to alter bridge init order
  drm/panel: Add prepare_prev_first flag to drm_panel
  drm/bridge: Document the expected behaviour of DSI host controllers

Sam Ravnborg (2):
  drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs
  drm/bridge: Drop unused drm_bridge_chain functions

 Documentation/gpu/drm-kms-helpers.rst  |   7 +
 drivers/gpu/drm/bridge/panel.c |   2 +
 drivers/gpu/drm/bridge/parade-ps8640.c |  18 +-
 drivers/gpu/drm/drm_bridge.c   | 294 ++---
 drivers/gpu/drm/mediatek/mtk_dp.c  |   4 +-
 include/drm/drm_bridge.h   |  36 +--
 include/drm/drm_panel.h|  10 +
 7 files changed, 201 insertions(+), 170 deletions(-)

-- 
2.34.1



Re: [PATCH v8 06/14] drm: bridge: samsung-dsim: Handle proper DSI host initialization

2022-12-05 Thread Dave Stevenson
Hi Frieder

On Mon, 5 Dec 2022 at 07:30, Frieder Schrempf
 wrote:
>
> On 02.12.22 15:55, Dave Stevenson wrote:
> > Hi Marek
> >
> > On Fri, 2 Dec 2022 at 12:21, Marek Vasut  wrote:
> >>
> >> On 12/2/22 11:52, Marek Szyprowski wrote:
> >>> Hi,
> >>>
> >>> Sorry for delay, I was on a sick leave last 2 weeks.
> >>>
> >>> On 28.11.2022 15:43, Jagan Teki wrote:
> >>>> ,On Sat, Nov 26, 2022 at 3:44 AM Marek Vasut  wrote:
> >>>>> On 11/23/22 21:09, Jagan Teki wrote:
> >>>>>> On Sat, Nov 19, 2022 at 7:45 PM Marek Vasut  wrote:
> >>>>>>> On 11/17/22 14:04, Marek Szyprowski wrote:
> >>>>>>>> On 17.11.2022 05:58, Marek Vasut wrote:
> >>>>>>>>> On 11/10/22 19:38, Jagan Teki wrote:
> >>>>>>>>>> DSI host initialization handling in previous exynos dsi driver has
> >>>>>>>>>> some pitfalls. It initializes the host during host transfer() hook
> >>>>>>>>>> that is indeed not the desired call flow for I2C and any other DSI
> >>>>>>>>>> configured downstream bridges.
> >>>>>>>>>>
> >>>>>>>>>> Host transfer() is usually triggered for downstream DSI panels or
> >>>>>>>>>> bridges and I2C-configured-DSI bridges miss these host 
> >>>>>>>>>> initialization
> >>>>>>>>>> as these downstream bridges use bridge operations hooks like 
> >>>>>>>>>> pre_enable,
> >>>>>>>>>> and enable in order to initialize or set up the host.
> >>>>>>>>>>
> >>>>>>>>>> This patch is trying to handle the host init handler to satisfy all
> >>>>>>>>>> downstream panels and bridges. Added the DSIM_STATE_REINITIALIZED 
> >>>>>>>>>> state
> >>>>>>>>>> flag to ensure that host init is also done on first cmd transfer, 
> >>>>>>>>>> this
> >>>>>>>>>> helps existing DSI panels work on exynos platform (form Marek
> >>>>>>>>>> Szyprowski).
> >>>>>>>>>>
> >>>>>>>>>> v8, v7, v6, v5:
> >>>>>>>>>> * none
> >>>>>>>>>>
> >>>>>>>>>> v4:
> >>>>>>>>>> * update init handling to ensure host init done on first cmd 
> >>>>>>>>>> transfer
> >>>>>>>>>>
> >>>>>>>>>> v3:
> >>>>>>>>>> * none
> >>>>>>>>>>
> >>>>>>>>>> v2:
> >>>>>>>>>> * check initialized state in samsung_dsim_init
> >>>>>>>>>>
> >>>>>>>>>> v1:
> >>>>>>>>>> * keep DSI init in host transfer
> >>>>>>>>>>
> >>>>>>>>>> Signed-off-by: Marek Szyprowski 
> >>>>>>>>>> Signed-off-by: Jagan Teki 
> >>>>>>>>>> ---
> >>>>>>>>>>   drivers/gpu/drm/bridge/samsung-dsim.c | 25 
> >>>>>>>>>> +
> >>>>>>>>>>   include/drm/bridge/samsung-dsim.h |  5 +++--
> >>>>>>>>>>   2 files changed, 20 insertions(+), 10 deletions(-)
> >>>>>>>>>>
> >>>>>>>>>> diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c
> >>>>>>>>>> b/drivers/gpu/drm/bridge/samsung-dsim.c
> >>>>>>>>>> index bb1f45fd5a88..ec7e01ae02ea 100644
> >>>>>>>>>> --- a/drivers/gpu/drm/bridge/samsung-dsim.c
> >>>>>>>>>> +++ b/drivers/gpu/drm/bridge/samsung-dsim.c
> >>>>>>>>>> @@ -1234,12 +1234,17 @@ static void samsung_dsim_disable_irq(struct
> >>>>>>>>>> samsung_dsim *dsi)
> >>>>>>>>>>   disable_irq(dsi->irq);
> >>>>>>>>>>   }
> >>>>>>>&g

Re: [PATCH v8 06/14] drm: bridge: samsung-dsim: Handle proper DSI host initialization

2022-12-02 Thread Dave Stevenson
Hi Marek

On Fri, 2 Dec 2022 at 12:21, Marek Vasut  wrote:
>
> On 12/2/22 11:52, Marek Szyprowski wrote:
> > Hi,
> >
> > Sorry for delay, I was on a sick leave last 2 weeks.
> >
> > On 28.11.2022 15:43, Jagan Teki wrote:
> >> ,On Sat, Nov 26, 2022 at 3:44 AM Marek Vasut  wrote:
> >>> On 11/23/22 21:09, Jagan Teki wrote:
>  On Sat, Nov 19, 2022 at 7:45 PM Marek Vasut  wrote:
> > On 11/17/22 14:04, Marek Szyprowski wrote:
> >> On 17.11.2022 05:58, Marek Vasut wrote:
> >>> On 11/10/22 19:38, Jagan Teki wrote:
>  DSI host initialization handling in previous exynos dsi driver has
>  some pitfalls. It initializes the host during host transfer() hook
>  that is indeed not the desired call flow for I2C and any other DSI
>  configured downstream bridges.
> 
>  Host transfer() is usually triggered for downstream DSI panels or
>  bridges and I2C-configured-DSI bridges miss these host initialization
>  as these downstream bridges use bridge operations hooks like 
>  pre_enable,
>  and enable in order to initialize or set up the host.
> 
>  This patch is trying to handle the host init handler to satisfy all
>  downstream panels and bridges. Added the DSIM_STATE_REINITIALIZED 
>  state
>  flag to ensure that host init is also done on first cmd transfer, 
>  this
>  helps existing DSI panels work on exynos platform (form Marek
>  Szyprowski).
> 
>  v8, v7, v6, v5:
>  * none
> 
>  v4:
>  * update init handling to ensure host init done on first cmd transfer
> 
>  v3:
>  * none
> 
>  v2:
>  * check initialized state in samsung_dsim_init
> 
>  v1:
>  * keep DSI init in host transfer
> 
>  Signed-off-by: Marek Szyprowski 
>  Signed-off-by: Jagan Teki 
>  ---
>    drivers/gpu/drm/bridge/samsung-dsim.c | 25 
>  +
>    include/drm/bridge/samsung-dsim.h |  5 +++--
>    2 files changed, 20 insertions(+), 10 deletions(-)
> 
>  diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c
>  b/drivers/gpu/drm/bridge/samsung-dsim.c
>  index bb1f45fd5a88..ec7e01ae02ea 100644
>  --- a/drivers/gpu/drm/bridge/samsung-dsim.c
>  +++ b/drivers/gpu/drm/bridge/samsung-dsim.c
>  @@ -1234,12 +1234,17 @@ static void samsung_dsim_disable_irq(struct
>  samsung_dsim *dsi)
>    disable_irq(dsi->irq);
>    }
>    -static int samsung_dsim_init(struct samsung_dsim *dsi)
>  +static int samsung_dsim_init(struct samsung_dsim *dsi, unsigned int
>  flag)
>    {
>    const struct samsung_dsim_driver_data *driver_data =
>  dsi->driver_data;
>    +if (dsi->state & flag)
>  +return 0;
>  +
>    samsung_dsim_reset(dsi);
>  -samsung_dsim_enable_irq(dsi);
>  +
>  +if (!(dsi->state & DSIM_STATE_INITIALIZED))
>  +samsung_dsim_enable_irq(dsi);
>  if (driver_data->reg_values[RESET_TYPE] == DSIM_FUNCRST)
>    samsung_dsim_enable_lane(dsi, BIT(dsi->lanes) - 1);
>  @@ -1250,6 +1255,8 @@ static int samsung_dsim_init(struct
>  samsung_dsim *dsi)
>    samsung_dsim_set_phy_ctrl(dsi);
>    samsung_dsim_init_link(dsi);
>    +dsi->state |= flag;
>  +
>    return 0;
>    }
>    @@ -1269,6 +1276,10 @@ static void
>  samsung_dsim_atomic_pre_enable(struct drm_bridge *bridge,
>    }
>  dsi->state |= DSIM_STATE_ENABLED;
>  +
>  +ret = samsung_dsim_init(dsi, DSIM_STATE_INITIALIZED);
>  +if (ret)
>  +return;
>    }
>  static void samsung_dsim_atomic_enable(struct drm_bridge 
>  *bridge,
>  @@ -1458,12 +1469,9 @@ static ssize_t
>  samsung_dsim_host_transfer(struct mipi_dsi_host *host,
>    if (!(dsi->state & DSIM_STATE_ENABLED))
>    return -EINVAL;
>    -if (!(dsi->state & DSIM_STATE_INITIALIZED)) {
>  -ret = samsung_dsim_init(dsi);
>  -if (ret)
>  -return ret;
>  -dsi->state |= DSIM_STATE_INITIALIZED;
>  -}
>  +ret = samsung_dsim_init(dsi, DSIM_STATE_REINITIALIZED);
> >>> This triggers full controller reset and reprogramming upon first
> >>> command transfer, is such heavy handed reload really necessary ?
> >> Yes it is, otherwise the proper DSI panels doesn't work with Exynos DRM
> >> DSI. If this is a real issue 

[PATCH v3 1/5] drm/bridge: ps8640: Use atomic variants of drm_bridge_funcs

2022-12-02 Thread Dave Stevenson
From: Sam Ravnborg 

The atomic variants of enable/disable in drm_bridge_funcs are the
preferred operations - introduce these.

The ps8640 driver used the non-atomic variants of the 
drm_bridge_chain_pre_enable/
drm_bridge_chain_post_disable - convert these to the atomic variants.

v2:
  - Init state operations in drm_bridge_funcs (Laurent)

Signed-off-by: Sam Ravnborg 
Reviewed-by: Maxime Ripard 
Cc: Jitao Shi 
Cc: Enric Balletbo i Serra 
Cc: Philip Chen 
Cc: Andrzej Hajda 
Cc: Neil Armstrong 
Cc: Robert Foss 
Cc: Laurent Pinchart 
Cc: Jonas Karlman 
Cc: Jernej Skrabec 
Reviewed-by: Laurent Pinchart 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/bridge/parade-ps8640.c | 18 --
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c 
b/drivers/gpu/drm/bridge/parade-ps8640.c
index f74090a9cc9e..4b361d7d5e44 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -15,6 +15,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -442,7 +443,8 @@ static const struct dev_pm_ops ps8640_pm_ops = {
pm_runtime_force_resume)
 };
 
-static void ps8640_pre_enable(struct drm_bridge *bridge)
+static void ps8640_atomic_pre_enable(struct drm_bridge *bridge,
+struct drm_bridge_state *old_bridge_state)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
struct regmap *map = ps_bridge->regmap[PAGE2_TOP_CNTL];
@@ -476,7 +478,8 @@ static void ps8640_pre_enable(struct drm_bridge *bridge)
ps_bridge->pre_enabled = true;
 }
 
-static void ps8640_post_disable(struct drm_bridge *bridge)
+static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
+  struct drm_bridge_state 
*old_bridge_state)
 {
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
 
@@ -554,7 +557,7 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * EDID, for this chip, we need to do a full poweron, otherwise it will
 * fail.
 */
-   drm_bridge_chain_pre_enable(bridge);
+   drm_atomic_bridge_chain_pre_enable(bridge, connector->state->state);
 
edid = drm_get_edid(connector,
ps_bridge->page[PAGE0_DP_CNTL]->adapter);
@@ -564,7 +567,7 @@ static struct edid *ps8640_bridge_get_edid(struct 
drm_bridge *bridge,
 * before, return the chip to its original power state.
 */
if (poweroff)
-   drm_bridge_chain_post_disable(bridge);
+   drm_atomic_bridge_chain_post_disable(bridge, 
connector->state->state);
 
return edid;
 }
@@ -579,8 +582,11 @@ static const struct drm_bridge_funcs ps8640_bridge_funcs = 
{
.attach = ps8640_bridge_attach,
.detach = ps8640_bridge_detach,
.get_edid = ps8640_bridge_get_edid,
-   .post_disable = ps8640_post_disable,
-   .pre_enable = ps8640_pre_enable,
+   .atomic_post_disable = ps8640_atomic_post_disable,
+   .atomic_pre_enable = ps8640_atomic_pre_enable,
+   .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+   .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+   .atomic_reset = drm_atomic_helper_bridge_reset,
 };
 
 static int ps8640_bridge_get_dsi_resources(struct device *dev, struct ps8640 
*ps_bridge)
-- 
2.34.1



[PATCH v3 5/5] drm/bridge: Document the expected behaviour of DSI host controllers

2022-12-02 Thread Dave Stevenson
The exact behaviour of DSI host controllers is not specified,
therefore define it.

Signed-off-by: Dave Stevenson 
Reviewed-by: Laurent Pinchart 
---
 Documentation/gpu/drm-kms-helpers.rst |  7 +
 drivers/gpu/drm/drm_bridge.c  | 39 +++
 2 files changed, 46 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index a4860ffd6e86..b8ab05e42dbb 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -188,6 +188,13 @@ Bridge Helper Reference
 .. kernel-doc:: drivers/gpu/drm/drm_bridge.c
:export:
 
+MIPI-DSI bridge operation
+-
+
+.. kernel-doc:: drivers/gpu/drm/drm_bridge.c
+   :doc: dsi bridge operations
+
+
 Bridge Connector Helper Reference
 -
 
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 41051869d6bf..bd73d32f29c0 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -153,6 +153,45 @@
  * situation when probing.
  */
 
+/**
+ * DOC: dsi bridge operations
+ *
+ * DSI host interfaces are expected to be implemented as bridges rather than
+ * encoders, however there are a few aspects of their operation that need to
+ * be defined in order to provide a consistent interface.
+ *
+ * A DSI host should keep the PHY powered down until the pre_enable operation 
is
+ * called. All lanes are in an undefined idle state up to this point, and it
+ * must not be assumed that it is LP-11.
+ * pre_enable should initialise the PHY, set the data lanes to LP-11, and the
+ * clock lane to either LP-11 or HS depending on the mode_flag
+ * %MIPI_DSI_CLOCK_NON_CONTINUOUS.
+ *
+ * Ordinarily the downstream bridge DSI peripheral pre_enable will have been
+ * called before the DSI host. If the DSI peripheral requires LP-11 and/or
+ * the clock lane to be in HS mode prior to pre_enable, then it can set the
+ * _enable_prev_first flag to request the pre_enable (and
+ * post_disable) order to be altered to enable the DSI host first.
+ *
+ * Either the CRTC being enabled, or the DSI host enable operation should 
switch
+ * the host to actively transmitting video on the data lanes.
+ *
+ * The reverse also applies. The DSI host disable operation or stopping the 
CRTC
+ * should stop transmitting video, and the data lanes should return to the 
LP-11
+ * state. The DSI host _disable operation should disable the PHY.
+ * If the _enable_prev_first flag is set, then the DSI peripheral's
+ * bridge _disable will be called before the DSI host's post_disable.
+ *
+ * Whilst it is valid to call _transfer prior to pre_enable or after
+ * post_disable, the exact state of the lanes is undefined at this point. The
+ * DSI host should initialise the interface, transmit the data, and then 
disable
+ * the interface again.
+ *
+ * Ultra Low Power State (ULPS) is not explicitly supported by DRM. If
+ * implemented, it therefore needs to be handled entirely within the DSI Host
+ * driver.
+ */
+
 static DEFINE_MUTEX(bridge_lock);
 static LIST_HEAD(bridge_list);
 
-- 
2.34.1



[PATCH v3 4/5] drm/panel: Add prepare_prev_first flag to drm_panel

2022-12-02 Thread Dave Stevenson
Mapping to the drm_bridge flag pre_enable_prev_first,
add a new flag prepare_prev_first to drm_panel to allow
the panel driver to request that the upstream bridge should
be pre_enabled before the panel prepare.

Signed-off-by: Dave Stevenson 
Reviewed-by: Dmitry Baryshkov 
---
 drivers/gpu/drm/bridge/panel.c |  2 ++
 include/drm/drm_panel.h| 10 ++
 2 files changed, 12 insertions(+)

diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 216af76d0042..03c3274dc3d9 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -364,6 +364,8 @@ struct drm_bridge *devm_drm_panel_bridge_add_typed(struct 
device *dev,
devres_free(ptr);
}
 
+   bridge->pre_enable_prev_first = panel->prepare_prev_first;
+
return bridge;
 }
 EXPORT_SYMBOL(devm_drm_panel_bridge_add_typed);
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
index 994bfcdd84c5..432fab2347eb 100644
--- a/include/drm/drm_panel.h
+++ b/include/drm/drm_panel.h
@@ -188,6 +188,16 @@ struct drm_panel {
 * Panel entry in registry.
 */
struct list_head list;
+
+   /**
+* @prepare_prev_first:
+*
+* The previous controller should be prepared first, before the prepare
+* for the panel is called. This is largely required for DSI panels
+* where the DSI host controller should be initialised to LP-11 before
+* the panel is powered up.
+*/
+   bool prepare_prev_first;
 };
 
 void drm_panel_init(struct drm_panel *panel, struct device *dev,
-- 
2.34.1



[PATCH v3 2/5] drm/bridge: Drop unused drm_bridge_chain functions

2022-12-02 Thread Dave Stevenson
From: Sam Ravnborg 

The drm_bridge_chain_{pre_enable,enable,disable,post_disable} has no
users left and we have atomic variants that should be used.
Drop them so they do not gain new users.

Adjust a few comments to avoid references to the dropped functions.

Signed-off-by: Sam Ravnborg 
Reviewed-by: Maxime Ripard 
Reviewed-by: Laurent Pinchart 
Cc: Laurent Pinchart 
Cc: Maarten Lankhorst 
Cc: Maxime Ripard 
Cc: Thomas Zimmermann 
Cc: Andrzej Hajda 
Cc: Neil Armstrong 
Cc: Robert Foss 
Cc: Daniel Vetter 
Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/drm_bridge.c | 110 ---
 include/drm/drm_bridge.h |  28 -
 2 files changed, 138 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 1545c50fd1c8..bb7fc09267af 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -509,61 +509,6 @@ drm_bridge_chain_mode_valid(struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_valid);
 
-/**
- * drm_bridge_chain_disable - disables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.disable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called before
- * calling the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_disable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-   struct drm_bridge *iter;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_reverse(iter, >bridge_chain, chain_node) {
-   if (iter->funcs->disable)
-   iter->funcs->disable(iter);
-
-   if (iter == bridge)
-   break;
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_disable);
-
-/**
- * drm_bridge_chain_post_disable - cleans up after disabling all bridges in the
- *encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.post_disable op for all the bridges in the
- * encoder chain, starting from the first bridge to the last. These are called
- * after completing the encoder's prepare op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_post_disable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->post_disable)
-   bridge->funcs->post_disable(bridge);
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_post_disable);
-
 /**
  * drm_bridge_chain_mode_set - set proposed mode for all bridges in the
  *encoder chain
@@ -593,61 +538,6 @@ void drm_bridge_chain_mode_set(struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL(drm_bridge_chain_mode_set);
 
-/**
- * drm_bridge_chain_pre_enable - prepares for enabling all bridges in the
- *  encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.pre_enable op for all the bridges in the encoder
- * chain, starting from the last bridge to the first. These are called
- * before calling the encoder's commit op.
- *
- * Note: the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_pre_enable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-   struct drm_bridge *iter;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_reverse(iter, >bridge_chain, chain_node) {
-   if (iter->funcs->pre_enable)
-   iter->funcs->pre_enable(iter);
-
-   if (iter == bridge)
-   break;
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_pre_enable);
-
-/**
- * drm_bridge_chain_enable - enables all bridges in the encoder chain
- * @bridge: bridge control structure
- *
- * Calls _bridge_funcs.enable op for all the bridges in the encoder
- * chain, starting from the first bridge to the last. These are called
- * after completing the encoder's commit op.
- *
- * Note that the bridge passed should be the one closest to the encoder
- */
-void drm_bridge_chain_enable(struct drm_bridge *bridge)
-{
-   struct drm_encoder *encoder;
-
-   if (!bridge)
-   return;
-
-   encoder = bridge->encoder;
-   list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->enable)
-   bridge->funcs->enable(bridge);
-   }
-}
-EXPORT_SYMBOL(drm_bridge_chain_enable);
-
 /**
  * drm_atomic_bridge_chain_disable - disables all bridges in the encoder chain
  * @bridge: bridge control structure
diff --git a/include/drm/

[PATCH v3 3/5] drm/bridge: Introduce pre_enable_prev_first to alter bridge init order

2022-12-02 Thread Dave Stevenson
DSI sink devices typically want the DSI host powered up and configured
before they are powered up. pre_enable is the place this would normally
happen, but they are called in reverse order from panel/connector towards
the encoder, which is the "wrong" order.

Add a new flag pre_enable_prev_first that any bridge can set
to swap the order of pre_enable (and post_disable) for that and the
immediately previous bridge.
Should the immediately previous bridge also set the
pre_enable_prev_first flag, the previous bridge to that will be called
before either of those which requested pre_enable_prev_first.

eg:
- Panel
- Bridge 1
- Bridge 2 pre_enable_prev_first
- Bridge 3
- Bridge 4 pre_enable_prev_first
- Bridge 5 pre_enable_prev_first
- Bridge 6
- Encoder
Would result in pre_enable's being called as Panel, Bridge 1, Bridge 3,
Bridge 2, Bridge 6, Bridge 5, Bridge 4, Encoder.

Signed-off-by: Dave Stevenson 
---
 drivers/gpu/drm/drm_bridge.c | 144 +--
 include/drm/drm_bridge.h |   8 ++
 2 files changed, 128 insertions(+), 24 deletions(-)

diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index bb7fc09267af..41051869d6bf 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -581,6 +581,25 @@ void drm_atomic_bridge_chain_disable(struct drm_bridge 
*bridge,
 }
 EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
 
+static void drm_atomic_bridge_call_post_disable(struct drm_bridge *bridge,
+   struct drm_atomic_state 
*old_state)
+{
+   if (old_state && bridge->funcs->atomic_post_disable) {
+   struct drm_bridge_state *old_bridge_state;
+
+   old_bridge_state =
+   drm_atomic_get_old_bridge_state(old_state,
+   bridge);
+   if (WARN_ON(!old_bridge_state))
+   return;
+
+   bridge->funcs->atomic_post_disable(bridge,
+  old_bridge_state);
+   } else if (bridge->funcs->post_disable) {
+   bridge->funcs->post_disable(bridge);
+   }
+}
+
 /**
  * drm_atomic_bridge_chain_post_disable - cleans up after disabling all bridges
  *   in the encoder chain
@@ -592,36 +611,85 @@ EXPORT_SYMBOL(drm_atomic_bridge_chain_disable);
  * starting from the first bridge to the last. These are called after 
completing
  * _encoder_helper_funcs.atomic_disable
  *
+ * If a bridge sets @pre_enable_prev_first, then the @post_disable for that
+ * bridge will be called before the previous one to reverse the @pre_enable
+ * calling direction.
+ *
  * Note: the bridge passed should be the one closest to the encoder
  */
 void drm_atomic_bridge_chain_post_disable(struct drm_bridge *bridge,
  struct drm_atomic_state *old_state)
 {
struct drm_encoder *encoder;
+   struct drm_bridge *next, *limit;
 
if (!bridge)
return;
 
encoder = bridge->encoder;
+
list_for_each_entry_from(bridge, >bridge_chain, chain_node) {
-   if (bridge->funcs->atomic_post_disable) {
-   struct drm_bridge_state *old_bridge_state;
+   limit = NULL;
+
+   if (!list_is_last(>chain_node, >bridge_chain)) 
{
+   next = list_next_entry(bridge, chain_node);
+
+   if (next->pre_enable_prev_first) {
+   /* next bridge had requested that prev
+* was enabled first, so disabled last
+*/
+   limit = next;
+
+   /* Find the next bridge that has NOT requested
+* prev to be enabled first / disabled last
+*/
+   list_for_each_entry_from(next, 
>bridge_chain,
+chain_node) {
+   if (next->pre_enable_prev_first) {
+   next = list_prev_entry(next, 
chain_node);
+   limit = next;
+   break;
+   }
+   }
+
+   /* Call these bridges in reverse order */
+   list_for_each_entry_from_reverse(next, 
>bridge_chain,
+chain_node) {
+   if (next == bridge)
+   break;
+
+   
drm_atomic_bridge_call_post_disable(next,
+ 

  1   2   3   4   >