From b908c10ee0098ee768046389df354a4d70a5831c Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:50 +0530 Subject: spi: cadence-quadspi: flush posted register writes before INDAC access cqspi_indirect_read_execute() and cqspi_indirect_write_execute() first set the enable bit on APB region and then start reading/writing to the AHB region. On TI K3 SoCs these regions lie on different endpoints. This means that the order of the two operations is not guaranteed, and they might be reordered at the interconnect level. It is possible for the AHB write to be executed before the APB write to enable the indirect controller, causing the transaction to be invalid and the write erroring out. Read back the APB region write before accessing the AHB region to make sure the write got flushed and the race condition is eliminated. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra --- drivers/spi/spi-cadence-quadspi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 77c3c017b0d6..66d69608ea6f 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1314,6 +1314,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTRD_START_MASK, reg_base + CQSPI_REG_INDIRECTRD); + readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { if (!wait_for_completion_timeout(&cqspi->transfer_complete, @@ -1594,6 +1595,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata, reinit_completion(&cqspi->transfer_complete); writel(CQSPI_REG_INDIRECTWR_START_MASK, reg_base + CQSPI_REG_INDIRECTWR); + readl(reg_base + CQSPI_REG_INDIRECTWR); /* Flush posted write. */ + /* * As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access * Controller programming sequence, couple of cycles of -- cgit v1.2.3 From 2d7226230b41a3f722a2b7951d220a906257a320 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:51 +0530 Subject: spi: cadence-quadspi: flush posted register writes before DAC access cqspi_read_setup() and cqspi_write_setup() program the address width as the last step in the setup. This is likely to be immediately followed by a DAC region read/write. On TI K3 SoCs the DAC region is on a different endpoint from the register region. This means that the order of the two operations is not guaranteed, and they might be reordered at the interconnect level. It is possible that the DAC read/write goes through before the address width update goes through. In this situation if the previous command used a different address width the OSPI command is sent with the wrong number of address bytes, resulting in an invalid command and undefined behavior. Read back the size register to make sure the write gets flushed before accessing the DAC region. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/spi/spi-cadence-quadspi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 66d69608ea6f..b81a60581889 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1275,6 +1275,7 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } @@ -1570,6 +1571,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata, reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK; reg |= (op->addr.nbytes - 1); writel(reg, reg_base + CQSPI_REG_SIZE); + readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */ return 0; } -- cgit v1.2.3 From e29174df9a8042a26e8898bc46d12961174e9229 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:52 +0530 Subject: spi: cadence-quadspi: do not use memcpy_fromio() on 8D-8D-8D ops In 8D-8D-8D mode an odd number of bytes cannot be read from the flash since they would result in half a cycle being left over. memcpy_fromio() makes no guarantees of access width size. On arm64 it is a mix of 1-byte and 8-bytes accesses. On arm it is just 1-byte accesses. memcpy_fromio() cannot be trusted when 8D-8D-8D reads are involved. Instead, explicitly perfrom memcpy from the IO space for 8D-8D-8D ops by making sure no odd-length accesses are performed. Since this controller can be used on both arm and arm64 platforms, only 4-byte reads are used to make sure the same code works on both platforms. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/spi/spi-cadence-quadspi.c | 42 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index b81a60581889..7b89bcf20960 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2011,6 +2011,46 @@ err_unmap: return ret; } +static void cqspi_memcpy_fromio(const struct spi_mem_op *op, void *to, + const void __iomem *from, size_t count) +{ + if (op->data.buswidth == 8 && op->data.dtr) { + /* + * 8D-8D-8D ops with odd length should be rejected by + * supports_op() so no need to worry about that. + */ + while (count && !IS_ALIGNED((unsigned long)from, 4)) { + *(u16 *)to = __raw_readw(from); + from += 2; + to += 2; + count -= 2; + } + + /* + * The controller can work with both 32-bit and 64-bit + * platforms. 32-bit platforms won't have a readq. So use a + * readl instead. + */ + while (count >= 4) { + *(u32 *)to = __raw_readl(from); + from += 4; + to += 4; + count -= 4; + } + + while (count) { + *(u16 *)to = __raw_readw(from); + from += 2; + to += 2; + count -= 2; + } + + return; + } + + memcpy_fromio(to, from, count); +} + static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, const struct spi_mem_op *op) { @@ -2023,7 +2063,7 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, int ret; if (!cqspi->rx_chan || !virt_addr_valid(buf)) { - memcpy_fromio(buf, cqspi->ahb_base + from, len); + cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len); return 0; } -- cgit v1.2.3 From 4fcefeccdc1bef5ea0c86f4a1aab7e1d91744b8f Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:53 +0530 Subject: spi: cadence-quadspi: do not use DMA for reads smaller than 16 bytes For reads this small it does not make a lot of sense to go through DMA which usually has a significant setup overhead. The benefits of DMA are reaped in larger transfers. This is especially relevant in case a register is being polled. The DMA overhead will make the polling slower than it should be. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/spi/spi-cadence-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 7b89bcf20960..b989e39d0781 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -2062,7 +2062,7 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata, u_char *buf = op->data.buf.in; int ret; - if (!cqspi->rx_chan || !virt_addr_valid(buf)) { + if (!cqspi->rx_chan || !virt_addr_valid(buf) || len <= 16) { cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len); return 0; } -- cgit v1.2.3 From 1867806af3335d4c4c74fdcc9b0510db70d4a9bd Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:54 +0530 Subject: mtd: spi-nor: core: avoid odd length/address reads on 8D-8D-8D mode On Octal DTR capable flashes like Micron Xcella reads cannot start or end at an odd address in Octal DTR mode. Extra bytes need to be read at the start or end to make sure both the start address and length remain even. To avoid allocating too much extra memory, thereby putting unnecessary memory pressure on the system, the temporary buffer containing the extra padding bytes is capped at PAGE_SIZE bytes. The rest of the 2-byte aligned part should be read directly in the main buffer. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/mtd/spi-nor/core.c | 81 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index 6267753bf2b0..c4b835e00183 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1697,6 +1697,82 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor) return info; } +/* + * On Octal DTR capable flashes like Micron Xcella reads cannot start or + * end at an odd address in Octal DTR mode. Extra bytes need to be read + * at the start or end to make sure both the start address and length + * remain even. + */ +static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + u_char *tmp_buf; + size_t tmp_len; + loff_t start, end; + int ret, bytes_read; + + if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2)) + return spi_nor_read_data(nor, from, len, buf); + else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE) + return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE), + buf); + + tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + start = round_down(from, 2); + end = round_up(from + len, 2); + + /* + * Avoid allocating too much memory. The requested read length might be + * quite large. Allocating a buffer just as large (slightly bigger, in + * fact) would put unnecessary memory pressure on the system. + * + * For example if the read is from 3 to 1M, then this will read from 2 + * to 4098. The reads from 4098 to 1M will then not need a temporary + * buffer so they can proceed as normal. + */ + tmp_len = min_t(size_t, end - start, PAGE_SIZE); + + ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are read than actually requested, but that number can't be + * reported to the calling function or it will confuse its calculations. + * Calculate how many of the _requested_ bytes were read. + */ + bytes_read = ret; + + if (from != start) + ret -= from - start; + + /* + * Only account for extra bytes at the end if they were actually read. + * For example, if the total length was truncated because of temporary + * buffer size limit then the adjustment for the extra bytes at the end + * is not needed. + */ + if (start + bytes_read == end) + ret -= end - (from + len); + + if (ret < 0) { + ret = -EIO; + goto out; + } + + memcpy(buf, tmp_buf + (from - start), ret); +out: + kfree(tmp_buf); + return ret; +} + static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -1714,7 +1790,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, addr = spi_nor_convert_addr(nor, addr); - ret = spi_nor_read_data(nor, addr, len, buf); + if (nor->read_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_read(nor, addr, len, buf); + else + ret = spi_nor_read_data(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; -- cgit v1.2.3 From b1d5329addbbdd443a0cdea23a3c2148b70df7b1 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:55 +0530 Subject: mtd: spi-nor: core: avoid odd length/address writes in 8D-8D-8D mode On Octal DTR capable flashes like Micron Xcella the writes cannot start or end at an odd address in Octal DTR mode. Extra 0xff bytes need to be appended or prepended to make sure the start address and end address are even. 0xff is used because on NOR flashes a program operation can only flip bits from 1 to 0, not the other way round. 0 to 1 flip needs to happen via erases. Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/mtd/spi-nor/core.c | 72 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c index c4b835e00183..5adf607b2a90 100644 --- a/drivers/mtd/spi-nor/core.c +++ b/drivers/mtd/spi-nor/core.c @@ -1815,6 +1815,71 @@ read_err: return ret; } +/* + * On Octal DTR capable flashes like Micron Xcella the writes cannot start or + * end at an odd address in Octal DTR mode. Extra 0xff bytes need to be appended + * or prepended to make sure the start address and end address are even. 0xff is + * used because on NOR flashes a program operation can only flip bits from 1 to + * 0, not the other way round. 0 to 1 flip needs to happen via erases. + */ +static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len, + const u8 *buf) +{ + u8 *tmp_buf; + size_t bytes_written; + loff_t start, end; + int ret; + + if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2)) + return spi_nor_write_data(nor, to, len, buf); + + tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL); + if (!tmp_buf) + return -ENOMEM; + + memset(tmp_buf, 0xff, nor->params->page_size); + + start = round_down(to, 2); + end = round_up(to + len, 2); + + memcpy(tmp_buf + (to - start), buf, len); + + ret = spi_nor_write_data(nor, start, end - start, tmp_buf); + if (ret == 0) { + ret = -EIO; + goto out; + } + if (ret < 0) + goto out; + + /* + * More bytes are written than actually requested, but that number can't + * be reported to the calling function or it will confuse its + * calculations. Calculate how many of the _requested_ bytes were + * written. + */ + bytes_written = ret; + + if (to != start) + ret -= to - start; + + /* + * Only account for extra bytes at the end if they were actually + * written. For example, if for some reason the controller could only + * complete a partial write then the adjustment for the extra bytes at + * the end is not needed. + */ + if (start + bytes_written == end) + ret -= end - (to + len); + + if (ret < 0) + ret = -EIO; + +out: + kfree(tmp_buf); + return ret; +} + /* * Write an address range to the nor chip. Data must be written in * FLASH_PAGESIZE chunks. The address range may be any size provided @@ -1859,7 +1924,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, if (ret) goto write_err; - ret = spi_nor_write_data(nor, addr, page_remain, buf + i); + if (nor->write_proto == SNOR_PROTO_8_8_8_DTR) + ret = spi_nor_octal_dtr_write(nor, addr, page_remain, + buf + i); + else + ret = spi_nor_write_data(nor, addr, page_remain, + buf + i); if (ret < 0) goto write_err; written = ret; -- cgit v1.2.3 From 9ca1870d256cd80bc78d4ea05a0f3da5d1a6db65 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav Date: Sat, 9 Mar 2024 01:33:56 +0530 Subject: spi: cadence-quadspi: fix error check when finding rxhigh During PHY calibration the return code of cqspi_find_rx_high() is not assigned to 'ret'. So the check for failure will take the previous value of 'ret', which will always be 0 since it was already checked by the previous step. This means that the calibration procedure will always think that rxhigh is found even when it is not. Fix this by assigning the return value of cqspi_find_rx_high() to 'ret'. Fixes: be58a6d2184f ("spi: cadence-qspi: Tune PHY to allow running at higher frequencies") Reported-by: Brian Paiva Signed-off-by: Pratyush Yadav Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/spi/spi-cadence-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index b989e39d0781..e8d91523fc1f 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -617,7 +617,7 @@ static int cqspi_phy_calibrate(struct cqspi_flash_pdata *f_pdata, rxhigh.tx = rxlow.tx; rxhigh.read_delay = rxlow.read_delay; - cqspi_find_rx_high(f_pdata, mem, &rxhigh); + ret = cqspi_find_rx_high(f_pdata, mem, &rxhigh); if (ret) goto out; dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", rxhigh.rx, rxhigh.tx, -- cgit v1.2.3 From 286ef76358e23497fafb79548a696c3ae2470cd9 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Sat, 9 Mar 2024 01:33:57 +0530 Subject: spi: spi-cadence-quadspi: Disable DMA due to errata id i2285 As per errata id i2285 of AM64x Errata doc [1] BCDMA can only be used when data source and DMA descriptor source is on the same endpoint. In case of OSPI mem to mem DMA read, descriptor is in DDR while source data is in OSPI which may trigger above errata leading to read data corruption on AM64x SR1.0 devices. Therefore disable OSPI DMA on such SoCs. Subsequent SR versions are not affected. [1] https://www.ti.com/lit/er/sprz457e/sprz457e.pdf Signed-off-by: Vignesh Raghavendra Signed-off-by: Apurva Nandan --- drivers/spi/spi-cadence-quadspi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index e8d91523fc1f..b3f5a4e3577d 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #define CQSPI_NAME "cadence-qspi" @@ -2457,6 +2458,11 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi) return 0; } +static const struct soc_device_attribute k3_soc_devices[] = { + { .family = "AM64X", .revision = "SR1.0" }, + { /* sentinel */ } +}; + static int cqspi_probe(struct platform_device *pdev) { const struct cqspi_driver_platdata *ddata; @@ -2611,7 +2617,7 @@ static int cqspi_probe(struct platform_device *pdev) goto probe_setup_failed; } - if (cqspi->use_direct_mode) { + if (cqspi->use_direct_mode && !soc_device_match(k3_soc_devices)) { ret = cqspi_request_mmap_dma(cqspi); if (ret == -EPROBE_DEFER) goto probe_setup_failed; -- cgit v1.2.3 From 26d04e8ddb3f2a22ed9eecbd0b168da2a7ae9c0d Mon Sep 17 00:00:00 2001 From: Brandon Brnich Date: Fri, 8 Mar 2024 11:40:08 -0600 Subject: arm64: dts: ti: k3-j722s: E5010 JPEG Encoder Add support for IMG E5010 Stateful JPEG Encoder that supports baseline encoding for semiplanar YUV420 and YUV422. Signed-off-by: Brandon Brnich Reviewed-by: Devarsh Thakkar --- arch/arm64/boot/dts/ti/k3-j722s.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi index 9a1ba152901f..93c62289cebb 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi +++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi @@ -519,6 +519,17 @@ status = "disabled"; }; + e5010: e5010@fd20000 { + compatible = "img,e5010-jpeg-enc"; + reg = <0x00 0xfd20000 0x00 0x100>, + <0x00 0xfd20200 0x00 0x200>; + reg-names = "regjasper", "regmmu"; + clocks = <&k3_clks 201 0>; + clock-names = "core_clk"; + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; + interrupts = ; + }; + }; /* MCU domain overrides */ -- cgit v1.2.3 From daaed0cbab16c077dca398a69b3e9514145e4e54 Mon Sep 17 00:00:00 2001 From: Brandon Brnich Date: Fri, 8 Mar 2024 11:40:09 -0600 Subject: arm64: dts: ti: k3-j722s: Remove Invalid Interrupts Propery from main_pmx0 main_pmx0 node in J722s inherits properties from same node in the am62p dt. Interrupt was introduced[0] in am62p dt for IO daisy chain wake up. There is no IP that needs this interrupt on am62p. However, J722s uses this interrupt line for the IMG E5010 JPEG Encoder. [0]: https://git.ti.com/cgit/ti-linux-kernel/ti-linux-kernel/commit/?&id=678ec1b76016 Signed-off-by: Brandon Brnich Reviewed-by: Devarsh Thakkar --- arch/arm64/boot/dts/ti/k3-j722s-evm.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts index 85340a77fef6..b89841400cf1 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts @@ -231,6 +231,7 @@ &main_pmx0 { + /delete-property/ interrupts; main_i2c0_pins_default: main-i2c0-default-pins { pinctrl-single,pins = < J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */ -- cgit v1.2.3 From 7596cf0da0653c3a44ae25c6bdbd39ba3e7a96e3 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:56:55 +0530 Subject: net: ethernet: ti: icss_iep: Move the declarations to .h file With the declarations of struct and enum related to IEP present in .c file, it is not possible to access the structures in other source code files. So move the declarations from icss_iep.c to icss_iep.h. IEP's def_inc is derived from the IEP reference clock. Instead of using hard coded value, use the def_inc as this is safer when changing the reference clock value. Signed-off-by: Ravi Gunasekaran --- drivers/net/ethernet/ti/icss_iep.c | 72 ---------------------------------- drivers/net/ethernet/ti/icss_iep.h | 72 +++++++++++++++++++++++++++++++++- drivers/net/ethernet/ti/icssg_prueth.c | 3 +- drivers/net/ethernet/ti/icssg_qos.c | 3 +- 4 files changed, 75 insertions(+), 75 deletions(-) diff --git a/drivers/net/ethernet/ti/icss_iep.c b/drivers/net/ethernet/ti/icss_iep.c index 49652b1d005f..f8faba257a25 100644 --- a/drivers/net/ethernet/ti/icss_iep.c +++ b/drivers/net/ethernet/ti/icss_iep.c @@ -54,78 +54,6 @@ #define IEP_CAP_CFG_CAPNF_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n) + 1) #define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10) -enum { - ICSS_IEP_GLOBAL_CFG_REG, - ICSS_IEP_GLOBAL_STATUS_REG, - ICSS_IEP_COMPEN_REG, - ICSS_IEP_SLOW_COMPEN_REG, - ICSS_IEP_COUNT_REG0, - ICSS_IEP_COUNT_REG1, - ICSS_IEP_CAPTURE_CFG_REG, - ICSS_IEP_CAPTURE_STAT_REG, - - ICSS_IEP_CAP6_RISE_REG0, - ICSS_IEP_CAP6_RISE_REG1, - - ICSS_IEP_CAP7_RISE_REG0, - ICSS_IEP_CAP7_RISE_REG1, - - ICSS_IEP_CMP_CFG_REG, - ICSS_IEP_CMP_STAT_REG, - ICSS_IEP_CMP0_REG0, - ICSS_IEP_CMP0_REG1, - ICSS_IEP_CMP1_REG0, - ICSS_IEP_CMP1_REG1, - - ICSS_IEP_CMP8_REG0, - ICSS_IEP_CMP8_REG1, - ICSS_IEP_SYNC_CTRL_REG, - ICSS_IEP_SYNC0_STAT_REG, - ICSS_IEP_SYNC1_STAT_REG, - ICSS_IEP_SYNC_PWIDTH_REG, - ICSS_IEP_SYNC0_PERIOD_REG, - ICSS_IEP_SYNC1_DELAY_REG, - ICSS_IEP_SYNC_START_REG, - ICSS_IEP_MAX_REGS, -}; - -/** - * struct icss_iep_plat_data - Plat data to handle SoC variants - * @config: Regmap configuration data - * @reg_offs: register offsets to capture offset differences across SoCs - * @flags: Flags to represent IEP properties - */ -struct icss_iep_plat_data { - struct regmap_config *config; - u32 reg_offs[ICSS_IEP_MAX_REGS]; - u32 flags; -}; - -struct icss_iep { - struct device *dev; - void __iomem *base; - const struct icss_iep_plat_data *plat_data; - struct regmap *map; - struct device_node *client_np; - unsigned long refclk_freq; - int clk_tick_time; /* one refclk tick time in ns */ - struct ptp_clock_info ptp_info; - struct ptp_clock *ptp_clock; - struct mutex ptp_clk_mutex; /* PHC access serializer */ - spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ - u32 def_inc; - s16 slow_cmp_inc; - u32 slow_cmp_count; - const struct icss_iep_clockops *ops; - void *clockops_data; - u32 cycle_time_ns; - u32 perout_enabled; - bool pps_enabled; - int cap_cmp_irq; - u64 period; - u32 latch_enable; -}; - static u32 icss_iep_readl(struct icss_iep *iep, int reg) { return readl(iep->base + iep->plat_data->reg_offs[reg]); diff --git a/drivers/net/ethernet/ti/icss_iep.h b/drivers/net/ethernet/ti/icss_iep.h index 7aae5ede47c0..7df995bcbbb2 100644 --- a/drivers/net/ethernet/ti/icss_iep.h +++ b/drivers/net/ethernet/ti/icss_iep.h @@ -12,7 +12,77 @@ #include #include -struct icss_iep; +enum { + ICSS_IEP_GLOBAL_CFG_REG, + ICSS_IEP_GLOBAL_STATUS_REG, + ICSS_IEP_COMPEN_REG, + ICSS_IEP_SLOW_COMPEN_REG, + ICSS_IEP_COUNT_REG0, + ICSS_IEP_COUNT_REG1, + ICSS_IEP_CAPTURE_CFG_REG, + ICSS_IEP_CAPTURE_STAT_REG, + + ICSS_IEP_CAP6_RISE_REG0, + ICSS_IEP_CAP6_RISE_REG1, + + ICSS_IEP_CAP7_RISE_REG0, + ICSS_IEP_CAP7_RISE_REG1, + + ICSS_IEP_CMP_CFG_REG, + ICSS_IEP_CMP_STAT_REG, + ICSS_IEP_CMP0_REG0, + ICSS_IEP_CMP0_REG1, + ICSS_IEP_CMP1_REG0, + ICSS_IEP_CMP1_REG1, + + ICSS_IEP_CMP8_REG0, + ICSS_IEP_CMP8_REG1, + ICSS_IEP_SYNC_CTRL_REG, + ICSS_IEP_SYNC0_STAT_REG, + ICSS_IEP_SYNC1_STAT_REG, + ICSS_IEP_SYNC_PWIDTH_REG, + ICSS_IEP_SYNC0_PERIOD_REG, + ICSS_IEP_SYNC1_DELAY_REG, + ICSS_IEP_SYNC_START_REG, + ICSS_IEP_MAX_REGS, +}; + +/** + * struct icss_iep_plat_data - Plat data to handle SoC variants + * @config: Regmap configuration data + * @reg_offs: register offsets to capture offset differences across SoCs + * @flags: Flags to represent IEP properties + */ +struct icss_iep_plat_data { + struct regmap_config *config; + u32 reg_offs[ICSS_IEP_MAX_REGS]; + u32 flags; +}; + +struct icss_iep { + struct device *dev; + void __iomem *base; + const struct icss_iep_plat_data *plat_data; + struct regmap *map; + struct device_node *client_np; + unsigned long refclk_freq; + int clk_tick_time; /* one refclk tick time in ns */ + struct ptp_clock_info ptp_info; + struct ptp_clock *ptp_clock; + struct mutex ptp_clk_mutex; /* PHC access serializer */ + spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */ + u32 def_inc; + s16 slow_cmp_inc; + u32 slow_cmp_count; + const struct icss_iep_clockops *ops; + void *clockops_data; + u32 cycle_time_ns; + u32 perout_enabled; + bool pps_enabled; + int cap_cmp_irq; + u64 period; + u32 latch_enable; +}; /* Firmware specific clock operations */ struct icss_iep_clockops { diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c index 6ad92f40c71c..613b78775580 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg_prueth.c @@ -1486,7 +1486,8 @@ static void prueth_iep_settime(void *clockops_data, u64 ns) sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0); sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32; sc_desc.iepcount_set = ns % cycletime; - sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4 + /* Count from 0 to (cycle time)- emac->iep->def_inc */ + sc_desc.CMP0_current = cycletime - emac->iep->def_inc; memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc)); diff --git a/drivers/net/ethernet/ti/icssg_qos.c b/drivers/net/ethernet/ti/icssg_qos.c index 67551e3ffa86..811205f916c7 100644 --- a/drivers/net/ethernet/ti/icssg_qos.c +++ b/drivers/net/ethernet/ti/icssg_qos.c @@ -142,7 +142,8 @@ static int tas_set_trigger_list_change(struct prueth_emac *emac) u64 base_time; u64 cur_time; - cycle_time = admin_list->cycle_time - 4; /* -4ns to compensate for IEP wraparound time */ + /* subtract emac->iep->def_inc ns to compensate for IEP wrap around time */ + cycle_time = admin_list->cycle_time - emac->iep->def_inc; base_time = admin_list->base_time; cur_time = prueth_iep_gettime(emac, &sts); -- cgit v1.2.3 From 4670156ee7073e890934851fb43d429bb868892c Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:56:56 +0530 Subject: arm64: dts: ti: k3-am64-main: Switch ICSSG core clock to 333MHz In order to fully to support all the HSR offload features at 1G, more clock cycles are needed. So switch the ICSSG core clock from 250MHz to 333MHz. This switch to 333MHz is applicable for all 3 modes - MAC mode, Switch Mode and HSR Mode and improves performance as well. Performance update in dual mac mode With Core Clk @ 333MHz Tx throughput - 934 Mbps Rx throuhput - 914 Mbps, With core clk @ 250MHz, Tx throughput - 920 Mbps Rx throughput - 706 Mbps The improvement in performance is in alignment with the firmware team's understanding that Rx budget cycle is tight at 250MHz. Signed-off-by: Ravi Gunasekaran --- arch/arm64/boot/dts/ti/k3-am64-main.dtsi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi index ecf1a50f197c..2bf45e8dfde3 100644 --- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi +++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi @@ -1093,6 +1093,8 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x00 0x30000000 0x80000>; + assigned-clocks = <&k3_clks 81 0>; + assigned-clock-parents = <&k3_clks 81 2>; icssg0_mem: memories@0 { reg = <0x0 0x2000>, @@ -1118,7 +1120,7 @@ clocks = <&k3_clks 81 0>, /* icssg0_core_clk */ <&k3_clks 81 20>; /* icssg0_iclk */ assigned-clocks = <&icssg0_coreclk_mux>; - assigned-clock-parents = <&k3_clks 81 20>; + assigned-clock-parents = <&k3_clks 81 0>; }; icssg0_iepclk_mux: iepclk-mux@30 { @@ -1263,6 +1265,8 @@ #address-cells = <1>; #size-cells = <1>; ranges = <0x0 0x00 0x30080000 0x80000>; + assigned-clocks = <&k3_clks 82 0>; + assigned-clock-parents = <&k3_clks 82 2>; icssg1_mem: memories@0 { reg = <0x0 0x2000>, @@ -1288,7 +1292,7 @@ clocks = <&k3_clks 82 0>, /* icssg1_core_clk */ <&k3_clks 82 20>; /* icssg1_iclk */ assigned-clocks = <&icssg1_coreclk_mux>; - assigned-clock-parents = <&k3_clks 82 20>; + assigned-clock-parents = <&k3_clks 82 0>; }; icssg1_iepclk_mux: iepclk-mux@30 { -- cgit v1.2.3 From c6abd1410cce11168822ad71f9c344108aa3c6d0 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:56:57 +0530 Subject: net: ethernet: ti: icssg_prueth: Enable HSR Tx Tag and Rx Tag offload Add support to offload HSR Tx Tag Insertion and Rx Tag Removal and duplicate discard. Support for offloading these features needs ICSSG HSR FW version REL.HSR_1G_01.02.00.01. Steps to offload to HSR Tx Tag Insertion and Rx Tag Removal. ----------------------------------------------------------- Example assuming eth1, eth2 ports of ICSSG1 on AM64-EVM 1) Delete existing HSR interface ip link delete hsr0 2) Bring down the interfaces ip link set eth1 down ip link set eth2 down 3) Configure both interfaces to have same MAC address ip link set dev eth2 address 4) Enable HSR offload for both interfaces ethtool -K eth1 hsr-fwd-offload on ethtool -K eth1 hsr-dup-offload on ethtool -K eth1 hsr-tag-ins-offload on ethtool -K eth1 hsr-tag-rm-offload on ethtool -K eth2 hsr-fwd-offload on ethtool -K eth2 hsr-dup-offload on ethtool -K eth2 hsr-tag-ins-offload on ethtool -K eth2 hsr-tag-rm-offload on devlink dev param set platform/icssg1-eth \ name hsr_offload_mode \ value true cmode runtime 5) Bring up the interfaces ip link set eth1 up ip link set eth2 up 6) Create HSR interface and add slave interfaces to it ip link add name hsr0 type hsr slave1 eth1 slave2 eth2 \ supervision 45 version 1 7) Add IP address to the HSR interface ip addr add /24 dev hsr0 8) Bring up the HSR interface ip link set hsr0 up Switching back to Dual EMAC mode: --------------------------------- 1) Delete HSR interface ip link delete hsr0 2) Bring down the interfaces ip link set eth1 down ip link set eth2 down 3) Disable HSR port-to-port offloading mode, packet duplication ethtool -K eth1 hsr-fwd-offload off ethtool -K eth1 hsr-dup-offload off ethtool -K eth1 hsr-tag-ins-offload off ethtool -K eth1 hsr-tag-rm-offload off ethtool -K eth2 hsr-fwd-offload off ethtool -K eth2 hsr-dup-offload off ethtool -K eth2 hsr-tag-ins-offload off ethtool -K eth2 hsr-tag-rm-offload off devlink dev param set platform/icssg1-eth \ name hsr_offload_mode \ value false cmode runtime Note: 1) At the very least, hsr-fwd-offload must be enabled. Without offloading the port-to-port offload, other HSR offloads cannot be enabled. 2) Inorder to enable hsr-tag-ins-offload, hsr-dup-offload must also be enabled as these are tightly coupled in the firmware implementation. Signed-off-by: Ravi Gunasekaran --- drivers/net/ethernet/ti/icssg_config.c | 4 +++- drivers/net/ethernet/ti/icssg_config.h | 2 ++ drivers/net/ethernet/ti/icssg_prueth.c | 15 ++++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg_config.c b/drivers/net/ethernet/ti/icssg_config.c index aea2ae8a3ae9..9d34ec0cb682 100644 --- a/drivers/net/ethernet/ti/icssg_config.c +++ b/drivers/net/ethernet/ti/icssg_config.c @@ -551,7 +551,9 @@ static const struct icssg_r30_cmd emac_r32_bitmask[] = { {{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/ {{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/ {{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/ - {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/ + {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}}, /* VLAN UNWARE*/ + {{0xffff2000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* HSR_RX_OFFLOAD_ENABLE */ + {{0xdfff0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}} /* HSR_RX_OFFLOAD_DISABLE */ }; int emac_set_port_state(struct prueth_emac *emac, diff --git a/drivers/net/ethernet/ti/icssg_config.h b/drivers/net/ethernet/ti/icssg_config.h index ff61c66cec60..1f318884fa1b 100644 --- a/drivers/net/ethernet/ti/icssg_config.h +++ b/drivers/net/ethernet/ti/icssg_config.h @@ -81,6 +81,8 @@ enum icssg_port_state_cmd { ICSSG_EMAC_PORT_PREMPT_TX_DISABLE, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE, ICSSG_EMAC_PORT_VLAN_AWARE_DISABLE, + ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE, + ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE, ICSSG_EMAC_PORT_MAX_COMMANDS }; diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c index 613b78775580..b6b075bf64d0 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg_prueth.c @@ -67,7 +67,9 @@ #define DEFAULT_UNTAG_MASK 1 #define NETIF_PRUETH_HSR_OFFLOAD (NETIF_F_HW_HSR_FWD | \ - NETIF_F_HW_HSR_DUP) + NETIF_F_HW_HSR_DUP | \ + NETIF_F_HW_HSR_TAG_INS | \ + NETIF_F_HW_HSR_TAG_RM) /* CTRLMMR_ICSSG_RGMII_CTRL register bits */ #define ICSSG_CTRL_RGMII_ID_MODE BIT(24) @@ -75,6 +77,7 @@ #define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */ #define PRUETH_UNDIRECTED_PKT_DST_TAG 0 +#define PRUETH_UNDIRECTED_PKT_TAG_INS BIT(30) static void prueth_cleanup_rx_chns(struct prueth_emac *emac, struct prueth_rx_chn *rx_chn, @@ -875,6 +878,9 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_DUP)) dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG; + if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_TAG_INS)) + epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS; + cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id); k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma); cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len); @@ -1678,6 +1684,13 @@ static int emac_ndo_open(struct net_device *ndev) } } + if (prueth->is_hsr_offload_mode) { + if (ndev->features & NETIF_F_HW_HSR_TAG_RM) + emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE); + else + emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE); + } + flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET; writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow); ret = emac_fdb_flow_id_updated(emac); -- cgit v1.2.3 From 0553610ace3e1b55eda28ca15863146c90080d83 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:56:58 +0530 Subject: net: ethernet: ti: icssg_prueth: Fix processing NETDEV_CHANGEUPPER event In HSR mode, the netdev notifier does not take care of the unlinking event of the upper net device. Fix this. Signed-off-by: Ravi Gunasekaran --- drivers/net/ethernet/ti/icssg_prueth.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c index b6b075bf64d0..56a2f6c622b3 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg_prueth.c @@ -2702,16 +2702,20 @@ static int prueth_netdevice_event(struct notifier_block *unused, if ((ndev->features & NETIF_PRUETH_HSR_OFFLOAD) && is_hsr_master(info->upper_dev)) { - if (!prueth->hsr_dev) { - prueth->hsr_dev = info->upper_dev; - - icssg_class_set_host_mac_addr(prueth->miig_rt, - prueth->hsr_dev->dev_addr); - } else { - if (prueth->hsr_dev != info->upper_dev) { - dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n"); - return -EOPNOTSUPP; + if (info->linking) { + if (!prueth->hsr_dev) { + prueth->hsr_dev = info->upper_dev; + + icssg_class_set_host_mac_addr(prueth->miig_rt, + prueth->hsr_dev->dev_addr); + } else { + if (prueth->hsr_dev != info->upper_dev) { + dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n"); + return -EOPNOTSUPP; + } } + } else { + prueth->hsr_dev = NULL; } } -- cgit v1.2.3 From a082ce3b5578703fd9379919a1a9aab7c64e8c96 Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:56:59 +0530 Subject: net: hsr: hsr_slave: Fix the promiscuous mode commit 4322af8c3aec ("net: hsr: Disable promiscuous mode in offload mode") disables promiscuous mode of slave devices while creating an HSR interface. But while deleting the HSR interface, it does not take care of it. It decreases the promiscuous mode count, which eventually enables promiscuous mode on the slave devices when creating HSR interface again. Fix this by not decrementing the promiscuous mode count while deleting the HSR interface when offload is enabled. Fixes: 4322af8c3aec ("net: hsr: Disable promiscuous mode in offload mode") Signed-off-by: Ravi Gunasekaran --- net/hsr/hsr_slave.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c index fa81035321ae..1b6457f357bd 100644 --- a/net/hsr/hsr_slave.c +++ b/net/hsr/hsr_slave.c @@ -157,7 +157,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev, fail_rx_handler: netdev_upper_dev_unlink(dev, hsr_dev); fail_upper_dev_link: - if (port->hsr->fwd_offloaded) + if (!port->hsr->fwd_offloaded) dev_set_promiscuity(dev, -1); return res; @@ -220,7 +220,8 @@ void hsr_del_port(struct hsr_port *port) netdev_update_features(master->dev); dev_set_mtu(master->dev, hsr_get_max_mtu(hsr)); netdev_rx_handler_unregister(port->dev); - dev_set_promiscuity(port->dev, -1); + if (!port->hsr->fwd_offloaded) + dev_set_promiscuity(port->dev, -1); netdev_upper_dev_unlink(port->dev, master->dev); } -- cgit v1.2.3 From 902a51e8a5c8bf2f9efbd76a750665878dae063b Mon Sep 17 00:00:00 2001 From: Ravi Gunasekaran Date: Tue, 12 Mar 2024 15:57:00 +0530 Subject: net: ethernet: ti: icssg_prueth: Fix race condition for VLAN table access The VLAN table is a shared memory between the two ports/slices in a ICSSG cluster and this may lead to race condition when the common code paths for both ports are executed in different CPUs. Fix the race condition access by locking the shared memory access. Signed-off-by: Ravi Gunasekaran --- drivers/net/ethernet/ti/icssg_config.c | 11 +++++++++-- drivers/net/ethernet/ti/icssg_prueth.c | 1 + drivers/net/ethernet/ti/icssg_prueth.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/icssg_config.c b/drivers/net/ethernet/ti/icssg_config.c index 9d34ec0cb682..88dc611f0fc6 100644 --- a/drivers/net/ethernet/ti/icssg_config.c +++ b/drivers/net/ethernet/ti/icssg_config.c @@ -771,7 +771,10 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, { struct prueth *prueth = emac->prueth; struct prueth_vlan_tbl *tbl = prueth->vlan_tbl; - u8 fid_c1 = tbl[vid].fid_c1; + u8 fid_c1; + + spin_lock(&prueth->vtbl_lock); + fid_c1 = tbl[vid].fid_c1; /* FID_C1: bit0..2 port membership mask, * bit3..5 tagging mask for each port @@ -786,6 +789,7 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, } tbl[vid].fid_c1 = fid_c1; + spin_unlock(&prueth->vtbl_lock); } u16 icssg_get_pvid(struct prueth_emac *emac) @@ -848,15 +852,18 @@ int emac_fdb_erase_all(struct prueth_emac *emac) int emac_fdb_flush_multicast(struct prueth_emac *emac) { struct prueth *prueth = emac->prueth; + u8 port_mask = BIT(emac->port_id); int ret = 0; int i; ret = emac_fdb_erase_all(emac); + spin_lock(&prueth->vtbl_lock); for (i = 0; i < SZ_4K - 1; i++) { prueth->vlan_tbl[i].fid = i; - prueth->vlan_tbl[i].fid_c1 = 0; + prueth->vlan_tbl[i].fid_c1 &= ~(port_mask | port_mask << 3); } + spin_unlock(&prueth->vtbl_lock); return ret; } diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c index 56a2f6c622b3..f3d033723857 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.c +++ b/drivers/net/ethernet/ti/icssg_prueth.c @@ -3298,6 +3298,7 @@ static int prueth_probe(struct platform_device *pdev) icss_iep_init_fw(prueth->iep1); } + spin_lock_init(&prueth->vtbl_lock); /* setup netdev interfaces */ if (eth0_node) { ret = prueth_netdev_init(prueth, eth0_node); diff --git a/drivers/net/ethernet/ti/icssg_prueth.h b/drivers/net/ethernet/ti/icssg_prueth.h index 03ec5b8438c2..0534c3b256ea 100644 --- a/drivers/net/ethernet/ti/icssg_prueth.h +++ b/drivers/net/ethernet/ti/icssg_prueth.h @@ -330,6 +330,7 @@ struct prueth { unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN]; int default_vlan; struct devlink *devlink; + spinlock_t vtbl_lock; /* Lock for vtbl in shared memory */ }; struct emac_tx_ts_response { -- cgit v1.2.3 From e95ab06761fec6a87be4c948723b69bbe39a46fa Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 13 Mar 2024 11:18:12 +0530 Subject: drm/bridge: sii902x: Fix mode_valid hook Currently, mode_valid hook returns all mode as valid. Add the check for the maximum and minimum pixel clock that the bridge can support while validating a mode. Signed-off-by: Jayesh Choudhary Reviewed-by: Aradhya Bhatia --- drivers/gpu/drm/bridge/sii902x.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index bc48919b0a16..cf2af687dda3 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -163,6 +163,10 @@ #define SII902X_AUDIO_PORT_INDEX 3 +/* drm_display_mode clock is in kHz */ +#define SII902X_MIN_PIXEL_CLOCK 25000 +#define SII902X_MAX_PIXEL_CLOCK 165000 + struct sii902x { struct i2c_client *i2c; struct regmap *regmap; @@ -322,7 +326,11 @@ static int sii902x_get_modes(struct drm_connector *connector) static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - /* TODO: check mode */ + if (mode->clock < SII902X_MIN_PIXEL_CLOCK) + return MODE_CLOCK_LOW; + + if (mode->clock > SII902X_MAX_PIXEL_CLOCK) + return MODE_CLOCK_HIGH; return MODE_OK; } -- cgit v1.2.3 From f02a7a44f5bc286f215eaa4e0f464a5273d88daf Mon Sep 17 00:00:00 2001 From: Jayesh Choudhary Date: Wed, 13 Mar 2024 11:18:13 +0530 Subject: arm64: dts: ti: k3-j722s-evm: Add HDMI_LS_OE gpio-hog Add the gpio hog for HDMI_LS_OE for HDMI ESD device TPD12S016PWR. Without this signal pulled up, TPD12S016PWR is unable to pass through the I2C request to HDMI connector which results in EDID not being read. After that fallback mode 1024x768 and smaller resolutions are added as valid modes. Pull up the control pin HDMI_LS_OE to get EDID working. Signed-off-by: Jayesh Choudhary Reviewed-by: Udit Kumar --- arch/arm64/boot/dts/ti/k3-j722s-evm.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts index b89841400cf1..26257e7989f4 100644 --- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts @@ -526,6 +526,14 @@ output-low; line-name = "GPIO_OLDI_RSTn"; }; + + p05-hog { + /* P05 - HDMI_LS_OE */ + gpio-hog; + gpios = <5 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_LS_OE"; + }; }; sii9022: bridge-hdmi@3b { -- cgit v1.2.3 From 3bd654af3722499ceb55ea081377974417ca3e0f Mon Sep 17 00:00:00 2001 From: Devarsh Thakkar Date: Wed, 13 Mar 2024 21:22:14 +0530 Subject: media: platform: img: e5010: Re-enable hardware on system resume Re-enable hardware on system resume before resuming the v4l2 m2m jobs so that jobs that were queued prior to system suspend can be resumed back. This helps support scenario to resume back from active use-case where a jpeg encoding use-case was already running before system got suspended. Signed-off-by: Devarsh Thakkar --- drivers/media/platform/img/e5010/e5010-jpeg-enc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c index 34491939ce0b..ed60d82041a6 100644 --- a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c +++ b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c @@ -1674,6 +1674,12 @@ static int e5010_resume(struct device *dev) if (ret < 0) return ret; + ret = e5010_init_device(e5010_dev); + if (ret) { + dev_err(dev, "Failed to re-enable e5010 device\n"); + return ret; + } + v4l2_m2m_resume(e5010_dev->m2m_dev); return ret; } -- cgit v1.2.3 From fe3ab28ca3a220ce23f56b55250ac1e5305b8aa1 Mon Sep 17 00:00:00 2001 From: Sinthu Raja Date: Mon, 11 Mar 2024 12:52:12 +0530 Subject: arm: configs: omap5: enable support for Intel WiFi adapters Enable support to use Intel Wireless Next-Gen WiFi adapters for AM57x platform. Signed-off-by: Sinthu Raja Reviewed-by: Udit Kumar --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index c979fb22bf0e..e00f4078a533 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -184,6 +184,7 @@ CONFIG_BT_MRVL_SDIO=m CONFIG_BT_QCOMSMD=m CONFIG_CFG80211=m CONFIG_MAC80211=m +CONFIG_IWLWIFI=m CONFIG_RFKILL=y CONFIG_RFKILL_INPUT=y CONFIG_RFKILL_GPIO=y -- cgit v1.2.3 From 28a7bc1a4310a836fb07775ac090521cfd27e1a7 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:14 +0530 Subject: arm64: dts: ti: k3-am68-sk: Add overlay for v3link fusion Arducam's UC-A09 is a V3Link "mini" fusion board. [1] It can be used to connect multiple V3Link (and FPD-III) based cameras to TI EVMs using a single 22-pin FFC (4-lane) CSI2 connector. Add an overlay to support it on AM68 SK, Also while at it fix the missing symbol export on k3-am68-sk-fpdlink-fusion overlay. [1] https://www.arducam.com/downloads/datasheet/Arducam_V3Link_Datasheet.pdf Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 3 + .../boot/dts/ti/k3-am68-sk-v3link-fusion.dtso | 161 +++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 46386248e769..785760aa59eb 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -103,6 +103,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-bb-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-fpdlink-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-som-ddr-mem-carveout.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-fusion.dtbo @@ -171,6 +172,8 @@ DTC_FLAGS_k3-am62p5-sk += -@ DTC_FLAGS_k3-am62x-sk-csi2-v3link-fusion += -@ DTC_FLAGS_k3-am654-base-board += -@ DTC_FLAGS_k3-am68-sk-base-board += -@ +DTC_FLAGS_k3-am68-sk-fpdlink-fusion += -@ +DTC_FLAGS_k3-am68-sk-v3link-fusion += -@ DTC_FLAGS_k3-am69-sk += -@ DTC_FLAGS_k3-j7200-common-proc-board += -@ DTC_FLAGS_k3-j721e-beagleboneai64 += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso new file mode 100644 index 000000000000..04ae5d0fa1a5 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + + +/dts-v1/; +/plugin/; + +#include +#include "k3-pinctrl.h" + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp3 { + p01-hog { + /* CSI_MUX_SEL_2 */ + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI_MUX_SEL_2"; + }; +}; + +&main_i2c1 { + status = "okay"; + #address-cells = <1>; + #size-cells = <0>; + + i2c-switch@70 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x70>; + + /* CAM0 I2C */ + cam0_i2c: i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + cam1_i2c: i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; \ No newline at end of file -- cgit v1.2.3 From 8c1f5f2c8de6d1d657e2e4307f14cf09605a7612 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:15 +0530 Subject: arm64: dts: ti: k3-am69-sk: Add overlay for v3link fusion Arducam's UC-A09 is a V3Link "mini" fusion board. [1] It can be used to connect multiple V3Link (and FPD-III) based cameras to TI EVMs using a single 22-pin FFC (4-lane) CSI2 connector. Add an overlay to support it on AM69 SK, Also while at it fix the missing symbol export on k3-am69-sk-csi2-fpdlink-fusion overlay. [1] https://www.arducam.com/downloads/datasheet/Arducam_V3Link_Datasheet.pdf Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 3 + .../boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso | 156 +++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 785760aa59eb..297bb5a2cc79 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -123,6 +123,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-ddr-mem-carveout.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-rpi-cam-imx219.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb @@ -175,6 +176,8 @@ DTC_FLAGS_k3-am68-sk-base-board += -@ DTC_FLAGS_k3-am68-sk-fpdlink-fusion += -@ DTC_FLAGS_k3-am68-sk-v3link-fusion += -@ DTC_FLAGS_k3-am69-sk += -@ +DTC_FLAGS_k3-am69-sk-csi2-v3link-fusion += -@ +DTC_FLAGS_k3-am69-sk-fpdlink-fusion += -@ DTC_FLAGS_k3-j7200-common-proc-board += -@ DTC_FLAGS_k3-j721e-beagleboneai64 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso new file mode 100644 index 000000000000..988b6a6994d8 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp2 { + p01-hog { + /* P01 - CSI_MUX_SEL_2 */ + gpio-hog; + gpios = <1 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI_MUX_SEL_2"; + }; +}; + +&pca9543 { + #address-cells = <1>; + #size-cells = <0>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + port@0 { + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; +}; }; + +&cdns_csi2rx1 { + ports { + port@0 { + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy_rx0 { + status = "okay"; +}; + +&dphy_rx1 { + status = "okay"; +}; -- cgit v1.2.3 From b209b18a9ee558435ed3afd44a8177ef64e93f25 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:16 +0530 Subject: arm64: dts: ti: k3-j722s-evm: Add overlay for dual v3link fusion Arducam's UC-A09 is a V3Link "mini" fusion board. [1] It can be used to connect multiple V3Link (and FPD-III) based cameras to TI EVMs using a single 22-pin FFC (4-lane) CSI2 connector. Add an overlay to support it on J722S EVM. [1] https://www.arducam.com/downloads/datasheet/Arducam_V3Link_Datasheet.pdf Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 2 + .../boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso | 173 +++++++++++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 297bb5a2cc79..05558113faaa 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -117,6 +117,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-dsi-rpi-7inch-panel.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-microtips-mf101hie-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-v3link-fusion.dtbo # Boards with J784s4 SoC dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb @@ -187,5 +188,6 @@ DTC_FLAGS_k3-j721e-sk-fusion += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ DTC_FLAGS_k3-j721s2-evm-fusion += -@ DTC_FLAGS_k3-j722s-evm += -@ +DTC_FLAGS_k3-j722s-evm-v3link-fusion += -@ DTC_FLAGS_k3-j784s4-evm += -@ DTC_FLAGS_k3-am642-evm += -@ diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso new file mode 100644 index 000000000000..614198ca334c --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Arducam V3Link UC-A09 board + * https://www.arducam.com/fpd-link-3-cameras/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&exp1 { + p06-hog { + /* P06 - CSI01_MUX_SEL_2 */ + gpio-hog; + gpios = <6 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI01_MUX_SEL_2"; + }; + + p07-hog { + /* P01 - CSI23_MUX_SEL_2 */ + gpio-hog; + gpios = <7 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "CSI23_MUX_SEL_2"; + }; +}; + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + + /* CAM0 I2C */ + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; + + /* CAM1 I2C */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@30 { + compatible = "ti,ds90ub960-q1"; + reg = <0x30>; + + clock-names = "refclk"; + clocks = <&clk_fusion_25M_fixed>; + + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; -- cgit v1.2.3 From a9f5f1aaeade84ebb0e2aacd9ac1f69d1f533dd0 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:17 +0530 Subject: arm64: dts: ti: k3-j722s-evm: Add overlay for fusion board Fusion application board [1] can be used to connect multiple FPDLink-III based sensors to TI EVMs. Upto 8x sensors can simultaneously stream over the two CSI RX ports on J722S EVM. Link: https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ [1] Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 2 + .../boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso | 146 +++++++++++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 05558113faaa..b42f836f690d 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -116,6 +116,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-tevi-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-dsi-rpi-7inch-panel.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-fpdlink-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-microtips-mf101hie-panel.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-v3link-fusion.dtbo @@ -188,6 +189,7 @@ DTC_FLAGS_k3-j721e-sk-fusion += -@ DTC_FLAGS_k3-j721s2-common-proc-board += -@ DTC_FLAGS_k3-j721s2-evm-fusion += -@ DTC_FLAGS_k3-j722s-evm += -@ +DTC_FLAGS_k3-j722s-evm-fpdlink-fusion += -@ DTC_FLAGS_k3-j722s-evm-v3link-fusion += -@ DTC_FLAGS_k3-j784s4-evm += -@ DTC_FLAGS_k3-am642-evm += -@ diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso new file mode 100644 index 000000000000..380a4171ee50 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on J721E EVM + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_fusion_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + + +&pca9543_0 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>; + + ds90ub960_0_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_0_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy0>; + }; + }; + }; + + ds90ub960_0_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + deser@36 { + compatible = "ti,ds90ub960-q1"; + reg = <0x36>; + clocks = <&clk_fusion_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>; + + ds90ub960_1_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX */ + port@4 { + reg = <4>; + ds90ub960_1_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy1>; + }; + }; + }; + + ds90ub960_1_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + + }; +}; + +&cdns_csi2rx0 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi0_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy0: endpoint { + remote-endpoint = <&ds90ub960_0_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&cdns_csi2rx1 { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_port0: port@0 { + reg = <0>; + status = "okay"; + + csi2_phy1: endpoint { + remote-endpoint = <&ds90ub960_1_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx0 { + status = "okay"; +}; + +&dphy0 { + status = "okay"; +}; + +&ti_csi2rx1 { + status = "okay"; +}; + +&dphy1 { + status = "okay"; +}; -- cgit v1.2.3 From a99ee226326d12a293193b3018e6254c71b56631 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:18 +0530 Subject: arm64: dts: ti: k3-am69-sk: Add overlay for fusion EVM on CSI AUX port Fusion application board [1] can be used to connect multiple FPDLink-III based sensors to TI EVMs. Upto 12x sensors can simultaneously stream over the three CSI RX ports on J784S4/AM69, add an overlay to support the fusion board connected to CSI port 2(CSI_AUX port) on AM69 SK to enable 12 camera applications with AM69 SK. Link: https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ [1] Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 2 + .../dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso | 81 ++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index b42f836f690d..edc3eff41c4d 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -127,6 +127,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-ddr-mem-carveout.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-rpi-cam-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-v3link-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion-auxport.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-rpi-hdr-ehrpwm.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-csi2-ov5640.dtbo @@ -180,6 +181,7 @@ DTC_FLAGS_k3-am68-sk-v3link-fusion += -@ DTC_FLAGS_k3-am69-sk += -@ DTC_FLAGS_k3-am69-sk-csi2-v3link-fusion += -@ DTC_FLAGS_k3-am69-sk-fpdlink-fusion += -@ +DTC_FLAGS_k3-am69-sk-fpdlink-fusion-auxport += -@ DTC_FLAGS_k3-j7200-common-proc-board += -@ DTC_FLAGS_k3-j721e-beagleboneai64 += -@ DTC_FLAGS_k3-j721e-common-proc-board += -@ diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso new file mode 100644 index 000000000000..e3cc0bc36703 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DT Overlay for Fusion (FPD-Link III) board on AM69 SK CSI2 Aux Port + * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/ + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +&{/} { + clk_fusion1_25M_fixed: fixed-clock-25M { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + }; +}; + +&pca9543 { + #address-cells = <1>; + #size-cells = <0>; + + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + deser@3d { + compatible = "ti,ds90ub960-q1"; + reg = <0x3d>; + clocks = <&clk_fusion1_25M_fixed>; + clock-names = "refclk"; + i2c-alias-pool = <0x6a 0x6b 0x6c 0x6d 0x6e 0x6f>; + + ds90ub960_2_ports: ports { + #address-cells = <1>; + #size-cells = <0>; + + /* CSI-2 TX*/ + port@4 { + reg = <4>; + ds90ub960_2_csi_out: endpoint { + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + remote-endpoint = <&csi2_phy2>; + }; + }; + }; + + ds90ub960_2_links: links { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + }; +}; + +&cdns_csi2rx2 { + ports { + port@0 { + status = "okay"; + + csi2_phy2: endpoint { + remote-endpoint = <&ds90ub960_2_csi_out>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + link-frequencies = /bits/ 64 <800000000>; + }; + }; + }; +}; + +&ti_csi2rx2 { + status = "okay"; +}; + +&dphy_rx2 { + status = "okay"; +}; -- cgit v1.2.3 From 4d3502a8b8db0395db8ce0c6501795de2ec240c9 Mon Sep 17 00:00:00 2001 From: Vaishnav Achath Date: Wed, 13 Mar 2024 22:05:19 +0530 Subject: arm64: dts: ti: Add overlays for FPDLink IMX390 RCM on third CSI port IMX390 is a 2.1MP raw (bayer) sensor, the rugged camera module by D3 [1] packages it with an FPDLink-III serializer (DS90UB953) for use with sensor fusion setups using FPDLink-III deserializer boards. Add overlays for the cases when the modules are connected to ports on the DS90UB960 deserializer in fusion EVM when connected to third CSI port in a device like J784S4 or AM69. This helps to enable 12 camera use cases on AM69 SK. 1 - https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ Signed-off-by: Vaishnav Achath Acked-by: Jai Luthra Tested-by: Abhay Chirania --- arch/arm64/boot/dts/ti/Makefile | 6 +- .../boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso | 93 ++++++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso | 93 ++++++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso | 93 ++++++++++++++++++++++ .../boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso | 93 ++++++++++++++++++++++ 5 files changed, 377 insertions(+), 1 deletion(-) create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso create mode 100644 arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index edc3eff41c4d..529e6be613cd 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -154,7 +154,11 @@ dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-imx390-rcm-0-0.dtbo \ k3-fpdlink-imx390-rcm-1-0.dtbo \ k3-fpdlink-imx390-rcm-1-1.dtbo \ k3-fpdlink-imx390-rcm-1-2.dtbo \ - k3-fpdlink-imx390-rcm-1-3.dtbo + k3-fpdlink-imx390-rcm-1-3.dtbo \ + k3-fpdlink-imx390-rcm-2-0.dtbo \ + k3-fpdlink-imx390-rcm-2-1.dtbo \ + k3-fpdlink-imx390-rcm-2-2.dtbo \ + k3-fpdlink-imx390-rcm-2-3.dtbo dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \ k3-fpdlink-ov2312-0-1.dtbo \ k3-fpdlink-ov2312-0-2.dtbo \ diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso new file mode 100644 index 000000000000..3fc888a0d2fd --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 0 */ + port@0 { + reg = <0>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@0 { + reg = <0>; + i2c-alias = <0x64>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso new file mode 100644 index 000000000000..dc4d4ef71964 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 1 */ + port@1 { + reg = <1>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@1 { + reg = <1>; + i2c-alias = <0x65>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso new file mode 100644 index 000000000000..486b1fabe018 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 2 */ + port@2 { + reg = <2>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@2 { + reg = <2>; + i2c-alias = <0x66>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso new file mode 100644 index 000000000000..6b47107efba8 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IMX390 FPD-Link 3 Camera Module + * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/ + * + * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&ds90ub960_2_ports { + #address-cells = <1>; + #size-cells = <0>; + + /* FPDLink RX 3 */ + port@3 { + reg = <3>; + + ub960_fpd3_1_in: endpoint { + remote-endpoint = <&ub953_1_out>; + }; + }; +}; + +&ds90ub960_2_links { + #address-cells = <1>; + #size-cells = <0>; + + link@3 { + reg = <3>; + i2c-alias = <0x67>; + + ti,rx-mode = <3>; + + serializer: serializer { + compatible = "ti,ds90ub953-q1"; + gpio-controller; + #gpio-cells = <2>; + + #clock-cells = <0>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ub953_1_in: endpoint { + data-lanes = <1 2 3 4>; + remote-endpoint = <&sensor_1_out>; + }; + }; + + port@1 { + reg = <1>; + + ub953_1_out: endpoint { + remote-endpoint = <&ub960_fpd3_1_in>; + }; + }; + }; + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + sensor@1a { + compatible = "sony,imx390"; + reg = <0x1a>; + + clocks = <&serializer>; + clock-names = "inck"; + assigned-clocks = <&serializer>; + assigned-clock-rates = <27000000>; + + xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>; + error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>; + error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>; + comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>; + + port { + sensor_1_out: endpoint { + remote-endpoint = <&ub953_1_in>; + }; + }; + }; + }; + }; + }; +}; -- cgit v1.2.3 From 52d9c20eaefcb664425006ffe5a5733dd8153c63 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 13 Mar 2024 15:03:28 +0530 Subject: arm64: dts: ti: k3-j721e: Add overlay for J721E Infotainment Expansion Board J721E common processor board can be interfaced with the infotainment expansion board[0] to enable the following audio/video interfaces in addition to the peripherals provided by the common processor board: - Two Audio codecs each with three Stereo Inputs and four Stereo Outputs - Audio input over FPD Link III - Digital Audio Interface TX/RX - HDMI/FPD LINK III Display out - LI/OV Camera input Add support for TFP410 HDMI bridge located on the Infotainment Expansion Board (connected to J46 & J51). Add a HDMI connector node and connect the endpoints as below: DSS => TFP410 bridge => HDMI connector Also add the pinmux data and board muxes for DPI. Rest of the peripherals are missing as of now. [0]: Link: Signed-off-by: Tomi Valkeinen [j-choudhary@ti.com: minor cleanup] Signed-off-by: Jayesh Choudhary --- arch/arm64/boot/dts/ti/Makefile | 1 + .../k3-j721e-common-proc-board-infotainment.dtso | 164 +++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index 529e6be613cd..abc4b5a4352e 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -95,6 +95,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-ov5640.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-rpi-imx219.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-fusion.dtbo dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-rpi-hdr-ehrpwm.dtbo +dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board-infotainment.dtbo # Boards with J721s2 SoC dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso new file mode 100644 index 000000000000..65a7e54f0884 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Infotainment Expansion Board for j721e-evm + * User Guide: + * + * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include +#include + +#include "k3-pinctrl.h" + +&{/} { + hdmi-connector { + compatible = "hdmi-connector"; + label = "hdmi"; + type = "a"; + ddc-i2c-bus = <&main_i2c1>; + digital; + /* P12 - HDMI_HPD */ + hpd-gpios = <&exp6 10 GPIO_ACTIVE_HIGH>; + + port { + hdmi_connector_in: endpoint { + remote-endpoint = <&tfp410_out>; + }; + }; + }; + + dvi-bridge { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tfp410"; + /* P10 - HDMI_PDn */ + powerdown-gpios = <&exp6 8 GPIO_ACTIVE_LOW>; + + port@0 { + reg = <0>; + + tfp410_in: endpoint { + remote-endpoint = <&dpi_out0>; + pclk-sample = <1>; + }; + }; + + port@1 { + reg = <1>; + + tfp410_out: endpoint { + remote-endpoint = + <&hdmi_connector_in>; + }; + }; + }; +}; + +&main_pmx0 { + main_i2c1_exp6_pins_default: main-i2c1-exp6-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x264, PIN_INPUT, 7) /* (T29) MMC2_DAT2.GPIO1_24 */ + >; + }; + + dss_vout0_pins_default: dss-vout0-default-pins { + pinctrl-single,pins = < + J721E_IOPAD(0x58, PIN_OUTPUT, 10) /* (AE22) PRG1_PRU1_GPO0.VOUT0_DATA0 */ + J721E_IOPAD(0x5c, PIN_OUTPUT, 10) /* (AG23) PRG1_PRU1_GPO1.VOUT0_DATA1 */ + J721E_IOPAD(0x60, PIN_OUTPUT, 10) /* (AF23) PRG1_PRU1_GPO2.VOUT0_DATA2 */ + J721E_IOPAD(0x64, PIN_OUTPUT, 10) /* (AD23) PRG1_PRU1_GPO3.VOUT0_DATA3 */ + J721E_IOPAD(0x68, PIN_OUTPUT, 10) /* (AH24) PRG1_PRU1_GPO4.VOUT0_DATA4 */ + J721E_IOPAD(0x6c, PIN_OUTPUT, 10) /* (AG21) PRG1_PRU1_GPO5.VOUT0_DATA5 */ + J721E_IOPAD(0x70, PIN_OUTPUT, 10) /* (AE23) PRG1_PRU1_GPO6.VOUT0_DATA6 */ + J721E_IOPAD(0x74, PIN_OUTPUT, 10) /* (AC21) PRG1_PRU1_GPO7.VOUT0_DATA7 */ + J721E_IOPAD(0x78, PIN_OUTPUT, 10) /* (Y23) PRG1_PRU1_GPO8.VOUT0_DATA8 */ + J721E_IOPAD(0x7c, PIN_OUTPUT, 10) /* (AF21) PRG1_PRU1_GPO9.VOUT0_DATA9 */ + J721E_IOPAD(0x80, PIN_OUTPUT, 10) /* (AB23) PRG1_PRU1_GPO10.VOUT0_DATA10 */ + J721E_IOPAD(0x84, PIN_OUTPUT, 10) /* (AJ25) PRG1_PRU1_GPO11.VOUT0_DATA11 */ + J721E_IOPAD(0x88, PIN_OUTPUT, 10) /* (AH25) PRG1_PRU1_GPO12.VOUT0_DATA12 */ + J721E_IOPAD(0x8c, PIN_OUTPUT, 10) /* (AG25) PRG1_PRU1_GPO13.VOUT0_DATA13 */ + J721E_IOPAD(0x90, PIN_OUTPUT, 10) /* (AH26) PRG1_PRU1_GPO14.VOUT0_DATA14 */ + J721E_IOPAD(0x94, PIN_OUTPUT, 10) /* (AJ27) PRG1_PRU1_GPO15.VOUT0_DATA15 */ + J721E_IOPAD(0x30, PIN_OUTPUT, 10) /* (AF24) PRG1_PRU0_GPO11.VOUT0_DATA16 */ + J721E_IOPAD(0x34, PIN_OUTPUT, 10) /* (AJ24) PRG1_PRU0_GPO12.VOUT0_DATA17 */ + J721E_IOPAD(0x38, PIN_OUTPUT, 10) /* (AG24) PRG1_PRU0_GPO13.VOUT0_DATA18 */ + J721E_IOPAD(0x3c, PIN_OUTPUT, 10) /* (AD24) PRG1_PRU0_GPO14.VOUT0_DATA19 */ + J721E_IOPAD(0x40, PIN_OUTPUT, 10) /* (AC24) PRG1_PRU0_GPO15.VOUT0_DATA20 */ + J721E_IOPAD(0x44, PIN_OUTPUT, 10) /* (AE24) PRG1_PRU0_GPO16.VOUT0_DATA21 */ + J721E_IOPAD(0x24, PIN_OUTPUT, 10) /* (AJ20) PRG1_PRU0_GPO8.VOUT0_DATA22 */ + J721E_IOPAD(0x28, PIN_OUTPUT, 10) /* (AG20) PRG1_PRU0_GPO9.VOUT0_DATA23 */ + J721E_IOPAD(0x9c, PIN_OUTPUT, 10) /* (AC22) PRG1_PRU1_GPO17.VOUT0_DE */ + J721E_IOPAD(0x98, PIN_OUTPUT, 10) /* (AJ26) PRG1_PRU1_GPO16.VOUT0_HSYNC */ + J721E_IOPAD(0xa4, PIN_OUTPUT, 10) /* (AH22) PRG1_PRU1_GPO19.VOUT0_PCLK */ + J721E_IOPAD(0xa0, PIN_OUTPUT, 10) /* (AJ22) PRG1_PRU1_GPO18.VOUT0_VSYNC */ + >; + }; +}; + +&exp1 { + p14-hog { + /* P14 - VINOUT_MUX_SEL0 */ + gpio-hog; + gpios = <12 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "VINOUT_MUX_SEL0"; + }; + + p15-hog { + /* P15 - VINOUT_MUX_SEL1 */ + gpio-hog; + gpios = <13 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "VINOUT_MUX_SEL1"; + }; +}; + +&main_i2c1 { + /* i2c1 is used for DVI DDC, so we need to use 100kHz */ + clock-frequency = <100000>; + #address-cells = <1>; + #size-cells = <0>; + + exp6: gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&main_i2c1_exp6_pins_default>; + interrupt-parent = <&main_gpio1>; + interrupts = <24 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; + + p11-hog { + /* P11 - HDMI_DDC_OE */ + gpio-hog; + gpios = <9 GPIO_ACTIVE_HIGH>; + output-high; + line-name = "HDMI_DDC_OE"; + }; + }; +}; + +&dss { + pinctrl-names = "default"; + pinctrl-0 = <&dss_vout0_pins_default>; +}; + +&dss_ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dpi_out0: endpoint { + remote-endpoint = <&tfp410_in>; + }; + }; +}; -- cgit v1.2.3 From 43a9172360a59bc314979be22056e9c3d23c1695 Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Thu, 14 Mar 2024 16:55:40 +0530 Subject: HACK: media: v4l2-core: v4l2-ctrls-defs: Add custom IR exposure/gain The OX05B1S camera sensor supports both RGB and IR stream exposure/gain controls. The sensor has one source pad which gives out 2 streams: IR dominant (stream 0) and RGB dominant stream (stream 1). When programming the exposure/gain settings for the camera from a user space application like V4L2 user space API, we are unable to specify the stream for which the exposure/gain change is required. Hence, we have defined 3 custom control IDs for IR channel exposure, anologue and digital gain control. These custom controls added for IR channel are not an upstream acceptable solution and a better solution is required in the V4L2 framework for exposure/gain control in multistream sensors to remove this HACK. Signed-off-by: Abhishek Sharma --- drivers/media/v4l2-core/v4l2-ctrls-defs.c | 3 +++ include/uapi/linux/v4l2-controls.h | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c index e22921e7ea61..33c786eb1d90 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c @@ -793,6 +793,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component"; case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr"; case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB"; + case V4L2_CID_IR_EXPOSURE: return "Exposure, IR"; /* * Codec controls @@ -1111,6 +1112,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value"; case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value"; case V4L2_CID_NOTIFY_GAINS: return "Notify Gains"; + case V4L2_CID_IR_ANALOGUE_GAIN: return "Analogue Gain, IR"; /* Image processing controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1120,6 +1122,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_TEST_PATTERN: return "Test Pattern"; case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; case V4L2_CID_DIGITAL_GAIN: return "Digital Gain"; + case V4L2_CID_IR_DIGITAL_GAIN: return "Digital Gain, IR"; /* DV controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index d4a4e3cab3c2..1164694b12c1 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -148,8 +148,10 @@ enum v4l2_colorfx { #define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42) #define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43) +#define V4L2_CID_IR_EXPOSURE (V4L2_CID_BASE+44) + /* last CID + 1 */ -#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45) /* USER-class private control IDs */ @@ -1143,6 +1145,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7) #define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8) #define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9) +#define V4L2_CID_IR_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 10) /* Image processing controls */ @@ -1155,6 +1158,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) #define V4L2_CID_DEINTERLACING_MODE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 4) #define V4L2_CID_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 5) +#define V4L2_CID_IR_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 6) /* DV-class control IDs defined by V4L2 */ #define V4L2_CID_DV_CLASS_BASE (V4L2_CTRL_CLASS_DV | 0x900) -- cgit v1.2.3 From baed438193a0f3edf9ddb5cd652b6ecb8cb1c3da Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Thu, 14 Mar 2024 16:55:41 +0530 Subject: media: i2c: ox05b1s: add OmniVision OX05B1S driver OmniVision OX05B1S is an RGB-IR sensor, i.e. it uses a 4x4 R,G,B,Ir bayer pattern to capture both visible and near-infrared light. Every alternate frame, the sensor changes the exposure and the analogue/digital gain registers to stream an - A. IR-dominant frame on CSI-2 virtual channel 0 B. RGB-dominant frame on CSI-2 virtual channel 1 Both of these streams are captured at a resolution of 2592x1944, 30 fps each (60fps total). This driver also supports a few v4l2 controls like exposure and gain controls. The RGB dominant stream uses the normal v4l2 control identifiers (CIDs) for exposure and gain change while custom CIDs have been defined for the IR dominant stream. Signed-off-by: Abhishek Sharma --- drivers/media/i2c/Kconfig | 13 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/ox05b1s.c | 1139 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1153 insertions(+) create mode 100644 drivers/media/i2c/ox05b1s.c diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 3410f5093a9b..d97cd1924e19 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -720,6 +720,19 @@ config VIDEO_OV9734 To compile this driver as a module, choose M here: the module's name is ov9734. +config VIDEO_OX05B1S + tristate "OmniVision OX05B1S sensor support" + depends on OF_GPIO + depends on I2C && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help + This is a Video4Linux2 sensor driver for the OmniVision + OX05B1S camera. + + To compile this driver as a module, choose M here: the + module will be called OX05B1S. + config VIDEO_RDACM20 tristate "IMI RDACM20 camera support" depends on I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 0b1e811b4c13..aea3f7e03bfe 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -105,6 +105,7 @@ obj-$(CONFIG_VIDEO_OV9282) += ov9282.o obj-$(CONFIG_VIDEO_OV9640) += ov9640.o obj-$(CONFIG_VIDEO_OV9650) += ov9650.o obj-$(CONFIG_VIDEO_OV9734) += ov9734.o +obj-$(CONFIG_VIDEO_OX05B1S) += ox05b1s.o obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o diff --git a/drivers/media/i2c/ox05b1s.c b/drivers/media/i2c/ox05b1s.c new file mode 100644 index 000000000000..ab0c828e3948 --- /dev/null +++ b/drivers/media/i2c/ox05b1s.c @@ -0,0 +1,1139 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OmniVision OX05B1S RGB-IR Image Sensor driver + * + * Copyright (c) 2023-2024 Abhishek Sharma + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define OX05B_CHIP_ID 0x0558 +#define OX05B_FRAMERATE_DEFAULT 60 + +#define OX05B_OUT_WIDTH 2592 +#define OX05B_OUT_HEIGHT 1944 + +#define OX05B_SYS_MODE_SEL 0x0100 +#define OX05B_SC_CHIP_ID_HI 0x300a +#define OX05B_AEC_PK_EXPO_HI 0x3501 +#define OX05B_AEC_PK_EXPO_LO 0x3502 +#define OX05B_AEC_PK_AGAIN_HI 0x3508 +#define OX05B_AEC_PK_AGAIN_LO 0x3509 +#define OX05B_AEC_PK_DGAIN_HI 0x350a +#define OX05B_AEC_PK_DGAIN_LO 0x350b +#define OX05B_DEFAULT_LINK_FREQ 480000000 + +/* + * Exposure control + * Set max value as 0x850 (frame length = 2128) - 30 = 0x0832 for 16.66 ms exposure + * Set default value to be 1000 (0x03E8). + */ +#define OX05B_EXPOSURE_MAX 0x0832 +#define OX05B_EXPOSURE_DEFAULT 0x03E8 + +/* Analog gain control */ +#define OX05B_AGAIN_MAX 0x0F80 +#define OX05B_AGAIN_DEFAULT 0x010 + +/* Digital gain control */ +#define OX05B_DGAIN_MAX 0x0FFF +#define OX05B_DGAIN_DEFAULT 0x0100 + +static const struct v4l2_area ox05b_framesizes[] = { + { + .width = OX05B_OUT_WIDTH, + .height = OX05B_OUT_HEIGHT, + }, +}; + +static const u32 ox05b_mbus_formats[] = { + MEDIA_BUS_FMT_SBGGI10_1X10, +}; + +static const struct regmap_config ox05b_regmap_config = { + .reg_bits = 16, + .val_bits = 8, +}; + +static const s64 ox05b_link_freq_menu[] = { + OX05B_DEFAULT_LINK_FREQ, +}; + +static const struct reg_sequence ox05b_linear_2592x1944[] = { + {0x0107, 0x01}, {0x0104, 0x00}, {0x0301, 0x1a}, {0x0304, 0x01}, + {0x0305, 0xe0}, {0x0306, 0x04}, {0x0307, 0x01}, {0x0321, 0x03}, + {0x0324, 0x01}, {0x0325, 0x80}, {0x0341, 0x03}, {0x0344, 0x01}, + {0x0345, 0xb0}, {0x0347, 0x07}, {0x034b, 0x06}, {0x0360, 0x80}, + {0x040b, 0x5c}, {0x040c, 0xcd}, {0x2805, 0xff}, {0x2806, 0x0f}, + {0x3000, 0x00}, {0x3001, 0x00}, {0x3002, 0x10}, {0x3004, 0x00}, + {0x3009, 0x2e}, {0x3010, 0x41}, {0x3015, 0xf0}, {0x3016, 0xf0}, + {0x3017, 0xf0}, {0x3018, 0xf0}, {0x301a, 0x78}, {0x301b, 0xb4}, + {0x301f, 0xe9}, {0x3024, 0x80}, {0x302b, 0x00}, {0x3039, 0x00}, + {0x3044, 0x70}, {0x3101, 0x32}, {0x3182, 0x10}, {0x3187, 0xff}, + {0x320a, 0x00}, {0x320b, 0x00}, {0x320c, 0x00}, {0x320d, 0x00}, + {0x320e, 0x00}, {0x320f, 0x00}, {0x3211, 0x61}, {0x3212, 0x00}, + {0x3215, 0xcc}, {0x3218, 0x06}, {0x3251, 0x00}, {0x3252, 0xe4}, + {0x3253, 0x00}, {0x3304, 0x11}, {0x3305, 0x00}, {0x3306, 0x01}, + {0x3307, 0x00}, {0x3308, 0x02}, {0x3309, 0x00}, {0x330a, 0x02}, + {0x330b, 0x00}, {0x330c, 0x02}, {0x330d, 0x00}, {0x330e, 0x02}, + {0x330f, 0x00}, {0x3310, 0x02}, {0x3311, 0x00}, {0x3312, 0x02}, + {0x3313, 0x00}, {0x3314, 0x02}, {0x3315, 0x00}, {0x3316, 0x02}, + {0x3317, 0x11}, {0x3400, 0x0c}, {0x3421, 0x00}, {0x3422, 0x00}, + {0x3423, 0x00}, {0x3424, 0x00}, {0x3425, 0x00}, {0x3426, 0x00}, + {0x3427, 0x00}, {0x3428, 0x00}, {0x3429, 0x00}, {0x342a, 0x00}, + {0x342b, 0x00}, {0x342c, 0x00}, {0x342d, 0x00}, {0x342e, 0x00}, + {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x08}, {0x3503, 0xa8}, + {0x3504, 0x08}, {0x3505, 0x00}, {0x3506, 0x00}, {0x3507, 0x00}, + {0x3508, 0x01}, {0x3509, 0x00}, {0x350a, 0x01}, {0x350b, 0x00}, + {0x350c, 0x00}, {0x351e, 0x00}, {0x351f, 0x00}, {0x3541, 0x00}, + {0x3542, 0x08}, {0x3603, 0x65}, {0x3604, 0x24}, {0x3608, 0x08}, + {0x3610, 0x00}, {0x3612, 0x00}, {0x3619, 0x09}, {0x361a, 0x27}, + {0x3620, 0x40}, {0x3622, 0x15}, {0x3623, 0x0e}, {0x3624, 0x1f}, + {0x3625, 0x1f}, {0x362a, 0x01}, {0x362b, 0x00}, {0x3633, 0x88}, + {0x3634, 0x86}, {0x3636, 0x80}, {0x3638, 0x5b}, {0x363b, 0x22}, + {0x363c, 0x07}, {0x363d, 0x11}, {0x363e, 0x21}, {0x363f, 0x24}, + {0x3640, 0xd3}, {0x3641, 0x00}, {0x3650, 0xe4}, {0x3651, 0x80}, + {0x3652, 0xff}, {0x3653, 0x00}, {0x3654, 0x05}, {0x3655, 0xf8}, + {0x3656, 0x00}, {0x3660, 0x00}, {0x3664, 0x00}, {0x366a, 0x80}, + {0x366b, 0x00}, {0x3670, 0x00}, {0x3674, 0x00}, {0x3684, 0x6d}, + {0x3685, 0x6d}, {0x3686, 0x6d}, {0x3687, 0x6d}, {0x368c, 0x07}, + {0x368d, 0x07}, {0x368e, 0x07}, {0x368f, 0x07}, {0x3690, 0x04}, + {0x3691, 0x04}, {0x3692, 0x04}, {0x3693, 0x04}, {0x3698, 0x00}, + {0x369e, 0x1f}, {0x369f, 0x19}, {0x36a0, 0x05}, {0x36a2, 0x19}, + {0x36a3, 0x05}, {0x36a4, 0x07}, {0x36a5, 0x27}, {0x36a6, 0x00}, + {0x36a7, 0x80}, {0x36e3, 0x09}, {0x3700, 0x07}, {0x3701, 0x1b}, + {0x3702, 0x0a}, {0x3703, 0x21}, {0x3704, 0x19}, {0x3705, 0x07}, + {0x3706, 0x36}, {0x370a, 0x1c}, {0x370b, 0x02}, {0x370c, 0x00}, + {0x370d, 0x6e}, {0x370f, 0x80}, {0x3710, 0x10}, {0x3712, 0x09}, + {0x3714, 0x42}, {0x3715, 0x00}, {0x3716, 0x02}, {0x3717, 0xa2}, + {0x3718, 0x41}, {0x371a, 0x80}, {0x371b, 0x0a}, {0x371c, 0x0a}, + {0x371d, 0x08}, {0x371e, 0x01}, {0x371f, 0x20}, {0x3720, 0x0e}, + {0x3721, 0x22}, {0x3722, 0x0c}, {0x3727, 0x84}, {0x3728, 0x03}, + {0x3729, 0x64}, {0x372a, 0x0c}, {0x372b, 0x14}, {0x372d, 0x50}, + {0x372e, 0x14}, {0x3731, 0x11}, {0x3732, 0x24}, {0x3733, 0x00}, + {0x3734, 0x00}, {0x3735, 0x12}, {0x3736, 0x00}, {0x373b, 0x0b}, + {0x373c, 0x14}, {0x373f, 0x3e}, {0x3740, 0x12}, {0x3741, 0x12}, + {0x3753, 0x80}, {0x3754, 0x01}, {0x3756, 0x11}, {0x375c, 0x0f}, + {0x375d, 0x35}, {0x375e, 0x0f}, {0x375f, 0x37}, {0x3760, 0x0f}, + {0x3761, 0x27}, {0x3762, 0x3f}, {0x3763, 0x5d}, {0x3764, 0x01}, + {0x3765, 0x17}, {0x3766, 0x02}, {0x3768, 0x52}, {0x376a, 0x30}, + {0x376b, 0x02}, {0x376c, 0x08}, {0x376d, 0x2a}, {0x376e, 0x00}, + {0x376f, 0x18}, {0x3770, 0x2c}, {0x3771, 0x0c}, {0x3776, 0xc0}, + {0x3778, 0x00}, {0x3779, 0x80}, {0x377a, 0x00}, {0x377d, 0x14}, + {0x377e, 0x0c}, {0x379f, 0x00}, {0x37a3, 0x40}, {0x37a4, 0x03}, + {0x37a5, 0x10}, {0x37a6, 0x02}, {0x37a7, 0x0e}, {0x37a9, 0x00}, + {0x37aa, 0x08}, {0x37ab, 0x08}, {0x37ac, 0x36}, {0x37ad, 0x40}, + {0x37b0, 0x48}, {0x37d0, 0x00}, {0x37d1, 0x0b}, {0x37d2, 0x0c}, + {0x37d3, 0x10}, {0x37d4, 0x10}, {0x37d5, 0x10}, {0x37d8, 0x0e}, + {0x37d9, 0x0e}, {0x37da, 0x3c}, {0x37db, 0x52}, {0x37dc, 0x50}, + {0x37dd, 0x00}, {0x37de, 0x55}, {0x37df, 0x7d}, {0x37e5, 0x88}, + {0x37e7, 0x68}, {0x37e8, 0x07}, {0x37f0, 0x00}, {0x37f1, 0x0e}, + {0x37f2, 0x35}, {0x37f3, 0x14}, {0x37f4, 0x0c}, {0x37f5, 0x14}, + {0x37f6, 0x0c}, {0x37f7, 0x35}, {0x37f8, 0x35}, {0x37f9, 0x37}, + {0x37fa, 0x37}, {0x37fb, 0x37}, {0x3800, 0x00}, {0x3801, 0x00}, + {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0x0a}, {0x3805, 0x2f}, + {0x3806, 0x07}, {0x3807, 0xa7}, {0x3808, 0x0a}, {0x3809, 0x20}, + {0x380a, 0x07}, {0x380b, 0x98}, {0x380c, 0x01}, {0x380d, 0x78}, + {0x380e, 0x08}, {0x380f, 0x50}, {0x3810, 0x00}, {0x3811, 0x05}, + {0x3812, 0x00}, {0x3813, 0x08}, {0x3814, 0x11}, {0x3815, 0x11}, + {0x3820, 0x40}, {0x3821, 0x04}, {0x3822, 0x10}, {0x3823, 0x00}, + {0x3826, 0x00}, {0x3827, 0x00}, {0x382b, 0x03}, {0x382c, 0x0c}, + {0x382d, 0x15}, {0x382e, 0x01}, {0x3830, 0x00}, {0x3838, 0x00}, + {0x383b, 0x00}, {0x3840, 0x00}, {0x384a, 0xa2}, {0x3858, 0x00}, + {0x3859, 0x00}, {0x3860, 0x00}, {0x3861, 0x00}, {0x3866, 0x10}, + {0x3867, 0x07}, {0x3868, 0x01}, {0x3869, 0x01}, {0x386a, 0x01}, + {0x386b, 0x01}, {0x386c, 0x46}, {0x386d, 0x07}, {0x386e, 0xd2}, + {0x3871, 0x01}, {0x3872, 0x01}, {0x3873, 0x01}, {0x3874, 0x01}, + {0x3880, 0x00}, {0x3881, 0x00}, {0x3882, 0x00}, {0x3883, 0x00}, + {0x3884, 0x00}, {0x3885, 0x00}, {0x3886, 0x00}, {0x3887, 0x00}, + {0x3888, 0x00}, {0x3889, 0x00}, {0x3900, 0x13}, {0x3901, 0x19}, + {0x3902, 0x05}, {0x3903, 0x00}, {0x3904, 0x00}, {0x3908, 0x00}, + {0x3909, 0x18}, {0x390a, 0x00}, {0x390b, 0x11}, {0x390c, 0x15}, + {0x390d, 0x84}, {0x390f, 0x88}, {0x3910, 0x00}, {0x3911, 0x00}, + {0x3912, 0x03}, {0x3913, 0x62}, {0x3914, 0x00}, {0x3915, 0x06}, + {0x3916, 0x0c}, {0x3917, 0x81}, {0x3918, 0xc8}, {0x3919, 0x94}, + {0x391a, 0x17}, {0x391b, 0x05}, {0x391c, 0x81}, {0x391d, 0x05}, + {0x391e, 0x81}, {0x391f, 0x05}, {0x3920, 0x81}, {0x3921, 0x14}, + {0x3922, 0x0b}, {0x3929, 0x00}, {0x392a, 0x00}, {0x392b, 0xc8}, + {0x392c, 0x81}, {0x392f, 0x00}, {0x3930, 0x00}, {0x3931, 0x00}, + {0x3932, 0x00}, {0x3933, 0x00}, {0x3934, 0x1b}, {0x3935, 0xc0}, + {0x3936, 0x1c}, {0x3937, 0x21}, {0x3938, 0x0d}, {0x3939, 0x92}, + {0x393a, 0x85}, {0x393b, 0x8a}, {0x393c, 0x06}, {0x393d, 0x8b}, + {0x393e, 0x0f}, {0x393f, 0x14}, {0x3940, 0x0f}, {0x3941, 0x14}, + {0x3945, 0xc0}, {0x3946, 0x05}, {0x3947, 0xc0}, {0x3948, 0x01}, + {0x3949, 0x00}, {0x394a, 0x00}, {0x394b, 0x0b}, {0x394c, 0x0c}, + {0x394d, 0x0b}, {0x394e, 0x09}, {0x3951, 0xc7}, {0x3952, 0x0f}, + {0x3953, 0x0f}, {0x3954, 0x0f}, {0x3955, 0x00}, {0x3956, 0x27}, + {0x3957, 0x27}, {0x3958, 0x27}, {0x3959, 0x01}, {0x395a, 0x02}, + {0x395b, 0x14}, {0x395c, 0x36}, {0x395e, 0xc0}, {0x3964, 0x55}, + {0x3965, 0x55}, {0x3966, 0x88}, {0x3967, 0x88}, {0x3968, 0x66}, + {0x3969, 0x66}, {0x396d, 0x80}, {0x396e, 0xff}, {0x396f, 0x10}, + {0x3970, 0x80}, {0x3971, 0x80}, {0x3972, 0x00}, {0x397a, 0x55}, + {0x397b, 0x10}, {0x397c, 0x10}, {0x397d, 0x10}, {0x397e, 0x10}, + {0x3980, 0xfc}, {0x3981, 0xfc}, {0x3982, 0x66}, {0x3983, 0xfc}, + {0x3984, 0xfc}, {0x3985, 0x66}, {0x3986, 0x00}, {0x3987, 0x00}, + {0x3988, 0x00}, {0x3989, 0x00}, {0x398a, 0x00}, {0x398b, 0x00}, + {0x398c, 0x00}, {0x398d, 0x00}, {0x398e, 0x00}, {0x398f, 0x00}, + {0x3990, 0x00}, {0x3991, 0x00}, {0x3992, 0x00}, {0x3993, 0x00}, + {0x3994, 0x00}, {0x3995, 0x00}, {0x3996, 0x00}, {0x3997, 0x0f}, + {0x3998, 0x0c}, {0x3999, 0x0c}, {0x399a, 0x0c}, {0x399b, 0xf0}, + {0x399c, 0x14}, {0x399d, 0x0d}, {0x399e, 0x00}, {0x399f, 0x0c}, + {0x39a0, 0x0c}, {0x39a1, 0x0c}, {0x39a2, 0x00}, {0x39a3, 0x0f}, + {0x39a4, 0x0c}, {0x39a5, 0x0c}, {0x39a6, 0x0c}, {0x39a7, 0x0c}, + {0x39a8, 0x0f}, {0x39a9, 0xff}, {0x39aa, 0xbf}, {0x39ab, 0x3f}, + {0x39ac, 0x7e}, {0x39ad, 0xff}, {0x39ae, 0x00}, {0x39af, 0x00}, + {0x39b0, 0x00}, {0x39b1, 0x00}, {0x39b2, 0x00}, {0x39b3, 0x00}, + {0x39b4, 0x00}, {0x39b5, 0x00}, {0x39b6, 0x00}, {0x39b7, 0x00}, + {0x39b8, 0x00}, {0x39b9, 0x00}, {0x39ba, 0x00}, {0x39bb, 0x00}, + {0x39bc, 0x00}, {0x39c2, 0x00}, {0x39c3, 0x00}, {0x39c4, 0x00}, + {0x39c5, 0x00}, {0x39c7, 0x00}, {0x39c8, 0x00}, {0x39c9, 0x00}, + {0x39ca, 0x01}, {0x39cb, 0x00}, {0x39cc, 0x85}, {0x39cd, 0x09}, + {0x39cf, 0x04}, {0x39d0, 0x85}, {0x39d1, 0x09}, {0x39d2, 0x04}, + {0x39d4, 0x02}, {0x39d5, 0x0e}, {0x39db, 0x00}, {0x39dc, 0x01}, + {0x39dd, 0x0c}, {0x39e5, 0xff}, {0x39e6, 0xff}, {0x39fa, 0x38}, + {0x39fb, 0x07}, {0x39ff, 0x00}, {0x3a05, 0x00}, {0x3a06, 0x07}, + {0x3a07, 0x0d}, {0x3a08, 0x08}, {0x3a09, 0xb2}, {0x3a0a, 0x0a}, + {0x3a0b, 0x3c}, {0x3a0c, 0x0b}, {0x3a0d, 0xe1}, {0x3a0e, 0x03}, + {0x3a0f, 0x85}, {0x3a10, 0x0b}, {0x3a11, 0xff}, {0x3a12, 0x00}, + {0x3a13, 0x01}, {0x3a14, 0x0c}, {0x3a15, 0x04}, {0x3a17, 0x09}, + {0x3a18, 0x20}, {0x3a19, 0x09}, {0x3a1a, 0x9d}, {0x3a1b, 0x09}, + {0x3a1e, 0x34}, {0x3a1f, 0x09}, {0x3a20, 0x89}, {0x3a21, 0x09}, + {0x3a48, 0xbe}, {0x3a52, 0x00}, {0x3a53, 0x01}, {0x3a54, 0x0c}, + {0x3a55, 0x04}, {0x3a58, 0x0c}, {0x3a59, 0x04}, {0x3a5a, 0x01}, + {0x3a5b, 0x00}, {0x3a5c, 0x01}, {0x3a5d, 0xe8}, {0x3a62, 0x03}, + {0x3a63, 0x86}, {0x3a64, 0x0b}, {0x3a65, 0xbe}, {0x3a6a, 0xdc}, + {0x3a6b, 0x0b}, {0x3a6c, 0x1a}, {0x3a6d, 0x06}, {0x3a6e, 0x01}, + {0x3a6f, 0x04}, {0x3a70, 0xdc}, {0x3a71, 0x0b}, {0x3a83, 0x10}, + {0x3a84, 0x00}, {0x3a85, 0x08}, {0x3a87, 0x00}, {0x3a88, 0x6b}, + {0x3a89, 0x01}, {0x3a8a, 0x53}, {0x3a8f, 0x00}, {0x3a90, 0x00}, + {0x3a91, 0x00}, {0x3a92, 0x00}, {0x3a93, 0x60}, {0x3a94, 0xea}, + {0x3a98, 0x00}, {0x3a99, 0x31}, {0x3a9a, 0x01}, {0x3a9b, 0x04}, + {0x3a9c, 0xdc}, {0x3a9d, 0x0b}, {0x3aa4, 0x0f}, {0x3aad, 0x00}, + {0x3aae, 0x3e}, {0x3aaf, 0x02}, {0x3ab0, 0x77}, {0x3ab2, 0x00}, + {0x3ab3, 0x08}, {0x3ab6, 0x0b}, {0x3ab7, 0xff}, {0x3aba, 0x0b}, + {0x3abb, 0xfa}, {0x3abd, 0x05}, {0x3abe, 0x09}, {0x3abf, 0x1e}, + {0x3ac0, 0x00}, {0x3ac1, 0x63}, {0x3ac2, 0x01}, {0x3ac3, 0x55}, + {0x3ac8, 0x00}, {0x3ac9, 0x2a}, {0x3aca, 0x01}, {0x3acb, 0x36}, + {0x3acc, 0x00}, {0x3acd, 0x6f}, {0x3ad0, 0x00}, {0x3ad1, 0x79}, + {0x3ad2, 0x02}, {0x3ad3, 0x59}, {0x3ad4, 0x06}, {0x3ad5, 0x5a}, + {0x3ad6, 0x08}, {0x3ad7, 0x3a}, {0x3ad8, 0x00}, {0x3ad9, 0x79}, + {0x3ada, 0x02}, {0x3adb, 0x59}, {0x3adc, 0x09}, {0x3add, 0x89}, + {0x3ade, 0x0b}, {0x3adf, 0x69}, {0x3ae0, 0x03}, {0x3ae1, 0xc1}, + {0x3ae2, 0x0b}, {0x3ae3, 0xaf}, {0x3ae4, 0x00}, {0x3ae5, 0x3e}, + {0x3ae6, 0x02}, {0x3ae7, 0x77}, {0x3ae8, 0x00}, {0x3aea, 0x0b}, + {0x3aeb, 0xbe}, {0x3aee, 0x08}, {0x3aef, 0x80}, {0x3af0, 0x09}, + {0x3af1, 0x70}, {0x3af2, 0x08}, {0x3af3, 0x94}, {0x3af4, 0x09}, + {0x3af5, 0x5c}, {0x3af6, 0x03}, {0x3af7, 0x85}, {0x3af8, 0x08}, + {0x3af9, 0x80}, {0x3afa, 0x0b}, {0x3afb, 0xaf}, {0x3afc, 0x01}, + {0x3afd, 0x5a}, {0x3b1e, 0x00}, {0x3b20, 0xa5}, {0x3b21, 0x00}, + {0x3b22, 0x00}, {0x3b23, 0x00}, {0x3b24, 0x05}, {0x3b25, 0x00}, + {0x3b26, 0x00}, {0x3b27, 0x00}, {0x3b28, 0x1a}, {0x3b2f, 0x40}, + {0x3b40, 0x08}, {0x3b41, 0x70}, {0x3b42, 0x05}, {0x3b43, 0xf0}, + {0x3b44, 0x01}, {0x3b45, 0x54}, {0x3b46, 0x01}, {0x3b47, 0x54}, + {0x3b56, 0x08}, {0x3b80, 0x00}, {0x3b81, 0x00}, {0x3b82, 0x64}, + {0x3b83, 0x00}, {0x3b84, 0x00}, {0x3b85, 0x64}, {0x3b9d, 0x61}, + {0x3ba8, 0x38}, {0x3c11, 0x33}, {0x3c12, 0x3d}, {0x3c13, 0x00}, + {0x3c14, 0xbe}, {0x3c15, 0x0b}, {0x3c16, 0xa8}, {0x3c17, 0x03}, + {0x3c18, 0x9c}, {0x3c19, 0x0b}, {0x3c1a, 0x0f}, {0x3c1b, 0x97}, + {0x3c1c, 0x00}, {0x3c1d, 0x3c}, {0x3c1e, 0x02}, {0x3c1f, 0x78}, + {0x3c20, 0x06}, {0x3c21, 0x80}, {0x3c22, 0x08}, {0x3c23, 0x0f}, + {0x3c24, 0x97}, {0x3c25, 0x00}, {0x3c26, 0x3c}, {0x3c27, 0x02}, + {0x3c28, 0xa7}, {0x3c29, 0x09}, {0x3c2a, 0xaf}, {0x3c2b, 0x0b}, + {0x3c2c, 0x38}, {0x3c2d, 0xf9}, {0x3c2e, 0x0b}, {0x3c2f, 0xfd}, + {0x3c30, 0x05}, {0x3c35, 0x8c}, {0x3c3e, 0xc3}, {0x3c43, 0xcb}, + {0x3c44, 0x00}, {0x3c45, 0xff}, {0x3c46, 0x0b}, {0x3c48, 0x3b}, + {0x3c49, 0x40}, {0x3c4a, 0x00}, {0x3c4b, 0x5b}, {0x3c4c, 0x02}, + {0x3c4d, 0x02}, {0x3c4e, 0x00}, {0x3c4f, 0x04}, {0x3c50, 0x0c}, + {0x3c51, 0x00}, {0x3c52, 0x3b}, {0x3c53, 0x3a}, {0x3c54, 0x07}, + {0x3c55, 0x9e}, {0x3c56, 0x07}, {0x3c57, 0x9e}, {0x3c58, 0x07}, + {0x3c59, 0xe8}, {0x3c5a, 0x03}, {0x3c5b, 0x33}, {0x3c5c, 0xa8}, + {0x3c5d, 0x07}, {0x3c5e, 0xd0}, {0x3c5f, 0x07}, {0x3c60, 0x32}, + {0x3c61, 0x00}, {0x3c62, 0xd0}, {0x3c63, 0x07}, {0x3c64, 0x80}, + {0x3c65, 0x80}, {0x3c66, 0x3f}, {0x3c67, 0x01}, {0x3c68, 0x00}, + {0x3c69, 0xd0}, {0x3c6a, 0x07}, {0x3c6b, 0x01}, {0x3c6c, 0x00}, + {0x3c6d, 0xcd}, {0x3c6e, 0x07}, {0x3c6f, 0xd1}, {0x3c70, 0x07}, + {0x3c71, 0x01}, {0x3c72, 0x00}, {0x3c73, 0xc3}, {0x3c74, 0x01}, + {0x3c75, 0x00}, {0x3c76, 0xcd}, {0x3c77, 0x07}, {0x3c78, 0xea}, + {0x3c79, 0x03}, {0x3c7a, 0xcd}, {0x3c7b, 0x07}, {0x3c7c, 0x08}, + {0x3c7d, 0x06}, {0x3c7e, 0x03}, {0x3c85, 0x3a}, {0x3c86, 0x08}, + {0x3c87, 0x69}, {0x3c88, 0x0b}, {0x3c8f, 0xb2}, {0x3c90, 0x08}, + {0x3c91, 0xe1}, {0x3c92, 0x0b}, {0x3c93, 0x06}, {0x3c94, 0x03}, + {0x3c9b, 0x35}, {0x3c9c, 0x08}, {0x3c9d, 0x64}, {0x3c9e, 0x0b}, + {0x3ca5, 0xb7}, {0x3ca6, 0x08}, {0x3ca7, 0xe6}, {0x3ca8, 0x0b}, + {0x3ca9, 0x83}, {0x3caa, 0x3c}, {0x3cab, 0x01}, {0x3cac, 0x00}, + {0x3cad, 0x9e}, {0x3cae, 0x07}, {0x3caf, 0x85}, {0x3cb0, 0x03}, + {0x3cb1, 0xbc}, {0x3cb2, 0x0b}, {0x3cb7, 0x3c}, {0x3cb8, 0x01}, + {0x3cb9, 0x00}, {0x3cba, 0xbc}, {0x3cbb, 0x07}, {0x3cbc, 0xa3}, + {0x3cbd, 0x03}, {0x3cbe, 0x9e}, {0x3cbf, 0x0b}, {0x3cc4, 0x99}, + {0x3cc5, 0xe9}, {0x3cc6, 0x99}, {0x3cc7, 0xe9}, {0x3cc8, 0x33}, + {0x3cc9, 0x03}, {0x3cca, 0x33}, {0x3ccb, 0x03}, {0x3cce, 0x66}, + {0x3ccf, 0x66}, {0x3cd0, 0x00}, {0x3cd1, 0x04}, {0x3cd2, 0xf4}, + {0x3cd3, 0xb7}, {0x3cd4, 0x03}, {0x3cd5, 0x10}, {0x3cd6, 0x06}, + {0x3cd7, 0x30}, {0x3cd8, 0x08}, {0x3cd9, 0x5f}, {0x3cda, 0x0b}, + {0x3cdd, 0x44}, {0x3cde, 0x44}, {0x3cdf, 0x04}, {0x3ce0, 0x00}, + {0x3ce1, 0x00}, {0x3ce3, 0x00}, {0x3ce4, 0x00}, {0x3ce5, 0x00}, + {0x3ce6, 0x00}, {0x3ce7, 0x00}, {0x3ce8, 0x00}, {0x3ce9, 0x00}, + {0x3cea, 0x00}, {0x3ceb, 0x00}, {0x3cec, 0x00}, {0x3ced, 0x00}, + {0x3cee, 0x00}, {0x3cef, 0x85}, {0x3cf0, 0x03}, {0x3cf1, 0xaf}, + {0x3cf2, 0x0b}, {0x3cf3, 0x03}, {0x3cf4, 0x2c}, {0x3cf5, 0x00}, + {0x3cf6, 0x42}, {0x3cf7, 0x00}, {0x3cf8, 0x03}, {0x3cf9, 0x2c}, + {0x3cfa, 0x00}, {0x3cfb, 0x42}, {0x3cfc, 0x00}, {0x3cfd, 0x03}, + {0x3cfe, 0x01}, {0x3d81, 0x00}, {0x3e94, 0x0f}, {0x3e95, 0x5f}, + {0x3e96, 0x02}, {0x3e97, 0x3c}, {0x3e98, 0x00}, {0x3e9f, 0x00}, + {0x3f00, 0x00}, {0x3f05, 0x03}, {0x3f07, 0x01}, {0x3f08, 0x55}, + {0x3f09, 0x25}, {0x3f0a, 0x35}, {0x3f0b, 0x20}, {0x3f11, 0x05}, + {0x3f12, 0x05}, {0x3f40, 0x00}, {0x3f41, 0x03}, {0x3f43, 0x10}, + {0x3f44, 0x02}, {0x3f45, 0xe6}, {0x4000, 0xf9}, {0x4001, 0x2b}, + {0x4008, 0x04}, {0x4009, 0x1b}, {0x400a, 0x03}, {0x400e, 0x10}, + {0x4010, 0x04}, {0x4011, 0xf7}, {0x4032, 0x3e}, {0x4033, 0x02}, + {0x4050, 0x02}, {0x4051, 0x0d}, {0x40f9, 0x00}, {0x4200, 0x00}, + {0x4204, 0x00}, {0x4205, 0x00}, {0x4206, 0x00}, {0x4207, 0x00}, + {0x4208, 0x00}, {0x4244, 0x00}, {0x4300, 0x00}, {0x4301, 0xff}, + {0x4302, 0xf0}, {0x4303, 0x00}, {0x4304, 0xff}, {0x4305, 0xf0}, + {0x4306, 0x00}, {0x4308, 0x00}, {0x430a, 0x90}, {0x430b, 0x11}, + {0x4310, 0x00}, {0x4316, 0x00}, {0x431c, 0x00}, {0x431e, 0x00}, + {0x4410, 0x08}, {0x4433, 0x08}, {0x4434, 0xf8}, {0x4508, 0x80}, + {0x4509, 0x10}, {0x450b, 0x83}, {0x4511, 0x00}, {0x4580, 0x09}, + {0x4587, 0x00}, {0x458c, 0x00}, {0x4640, 0x00}, {0x4641, 0xc1}, + {0x4642, 0x00}, {0x4643, 0x00}, {0x4649, 0x00}, {0x4681, 0x04}, + {0x4682, 0x10}, {0x4683, 0xa0}, {0x4698, 0x07}, {0x4699, 0xf0}, + {0x4710, 0x00}, {0x4802, 0x00}, {0x481b, 0x3c}, {0x4837, 0x10}, + {0x4860, 0x00}, {0x4883, 0x00}, {0x4884, 0x09}, {0x4885, 0x80}, + {0x4886, 0x00}, {0x4888, 0x10}, {0x488b, 0x00}, {0x488c, 0x10}, + {0x4980, 0x03}, {0x4981, 0x06}, {0x4984, 0x00}, {0x4985, 0x00}, + {0x4a14, 0x04}, {0x4b01, 0x44}, {0x4b03, 0x80}, {0x4d06, 0xc8}, + {0x4d09, 0xdf}, {0x4d15, 0x7d}, {0x4d34, 0x7d}, {0x4d3c, 0x7d}, + {0x4f00, 0x7f}, {0x4f01, 0xff}, {0x4f03, 0x00}, {0x4f04, 0x18}, + {0x4f05, 0x13}, {0x5000, 0x6e}, {0x5001, 0x00}, {0x500a, 0x00}, + {0x5080, 0x00}, {0x5081, 0x00}, {0x5082, 0x00}, {0x5083, 0x00}, + {0x5100, 0x00}, {0x5103, 0x00}, {0x5180, 0x70}, {0x5181, 0x70}, + {0x5182, 0x73}, {0x5183, 0xff}, {0x5249, 0x06}, {0x524f, 0x06}, + {0x5281, 0x18}, {0x5282, 0x08}, {0x5283, 0x08}, {0x5284, 0x18}, + {0x5285, 0x18}, {0x5286, 0x08}, {0x5287, 0x08}, {0x5288, 0x18}, + {0x5289, 0x2d}, {0x6000, 0x40}, {0x6001, 0x40}, {0x6002, 0x00}, + {0x6003, 0x00}, {0x6004, 0x00}, {0x6005, 0x00}, {0x6006, 0x00}, + {0x6007, 0x00}, {0x6008, 0x00}, {0x6009, 0x00}, {0x600a, 0x00}, + {0x600b, 0x00}, {0x600c, 0x02}, {0x600d, 0x00}, {0x600e, 0x04}, + {0x600f, 0x00}, {0x6010, 0x06}, {0x6011, 0x00}, {0x6012, 0x00}, + {0x6013, 0x00}, {0x6014, 0x02}, {0x6015, 0x00}, {0x6016, 0x04}, + {0x6017, 0x00}, {0x6018, 0x06}, {0x6019, 0x00}, {0x601a, 0x01}, + {0x601b, 0x00}, {0x601c, 0x01}, {0x601d, 0x00}, {0x601e, 0x01}, + {0x601f, 0x00}, {0x6020, 0x01}, {0x6021, 0x00}, {0x6022, 0x01}, + {0x6023, 0x00}, {0x6024, 0x01}, {0x6025, 0x00}, {0x6026, 0x01}, + {0x6027, 0x00}, {0x6028, 0x01}, {0x6029, 0x00}, {0x3501, 0x08}, + {0x3502, 0x32}, {0x320a, 0x01}, {0x320b, 0x01}, {0x320c, 0x00}, + {0x320d, 0x00}, +}; + +struct ox05b { + struct device *dev; + struct clk *clk; + unsigned long clk_rate; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *pwdn_gpio; + struct v4l2_subdev subdev; + struct media_pad pad; + struct v4l2_mbus_framefmt format; + struct v4l2_ctrl_handler handler; + /* Added for RGB dominant stream */ + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *again; + struct v4l2_ctrl *dgain; + /* Added for IR dominant stream */ + struct v4l2_ctrl *ir_exposure; + struct v4l2_ctrl *ir_again; + struct v4l2_ctrl *ir_dgain; + u32 fps; + struct mutex lock; /* For streaming status */ + bool streaming; + struct v4l2_ctrl *link_freq; +}; + +static inline struct ox05b *to_ox05b(struct v4l2_subdev *sd) +{ + return container_of(sd, struct ox05b, subdev); +} + +static int ox05b_read(struct ox05b *ox05b, u16 addr, u32 *val, size_t nbytes) +{ + int ret; + __le32 val_le = 0; + + ret = regmap_bulk_read(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to read reg 0x%04x: %d\n", + __func__, addr, ret); + return ret; + } + + *val = le32_to_cpu(val_le); + return 0; +} + +static int ox05b_write(struct ox05b *ox05b, u16 addr, u32 val, size_t nbytes) +{ + int ret; + __le32 val_le = cpu_to_le32(val); + + ret = regmap_bulk_write(ox05b->regmap, addr, &val_le, nbytes); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg 0x%04x: %d\n", + __func__, addr, ret); + } + return ret; +} + +static int ox05b_write_table(struct ox05b *ox05b, + const struct reg_sequence *regs, + unsigned int nr_regs) +{ + int ret; + + ret = regmap_multi_reg_write(ox05b->regmap, regs, nr_regs); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to write reg table (%d)!\n", + __func__, ret); + } + return ret; +} + +static void ox05b_init_formats(struct v4l2_subdev_state *state) +{ + struct v4l2_mbus_framefmt *format; + int i; + + for (i = 0; i < 2; ++i) { + format = v4l2_subdev_state_get_stream_format(state, 0, i); + format->code = ox05b_mbus_formats[0]; + format->width = ox05b_framesizes[0].width; + format->height = ox05b_framesizes[0].height; + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + } +} + +static int ox05b_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct ox05b *ox05b = to_ox05b(sd); + struct v4l2_mbus_framefmt *format; + const struct v4l2_area *fsize; + u32 code; + int ret = 0; + + if (fmt->pad != 0) + return -EINVAL; + + if (fmt->stream != 0) + return -EINVAL; + + /* Sensor only supports a single format. */ + code = ox05b_mbus_formats[0]; + + /* Find the nearest supported frame size. */ + fsize = v4l2_find_nearest_size(ox05b_framesizes, + ARRAY_SIZE(ox05b_framesizes), width, + height, fmt->format.width, + fmt->format.height); + + format = v4l2_subdev_state_get_stream_format(state, fmt->pad, fmt->stream); + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ox05b->streaming) + ret = -EBUSY; + + format->code = code; + format->width = fsize->width; + format->height = fsize->height; + + fmt->format = *format; + + return ret; +} + +static int _ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] = { + { + .source_pad = 0, + .source_stream = 0, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + { + .source_pad = 0, + .source_stream = 1, + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing = { + .num_routes = ARRAY_SIZE(routes), + .routes = routes, + }; + + int ret; + + ret = v4l2_subdev_set_routing(sd, state, &routing); + if (ret < 0) + return ret; + + ox05b_init_formats(state); + + return 0; +} + +static int ox05b_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct v4l2_subdev_state *state; + struct v4l2_mbus_framefmt *fmt; + u32 bpp; + int ret = 0; + unsigned int i; + + if (pad != 0) + return -EINVAL; + state = v4l2_subdev_lock_and_get_active_state(sd); + fmt = v4l2_subdev_state_get_stream_format(state, 0, 0); + if (!fmt) { + ret = -EPIPE; + goto out; + } + memset(fd, 0, sizeof(*fd)); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + + /* pixel stream - 2 virtual channels*/ + + bpp = 10; + + for (i = 0; i < 2; ++i) { + fd->entry[fd->num_entries].stream = i; + + fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX; + fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8; + fd->entry[fd->num_entries].pixelcode = fmt->code; + fd->entry[fd->num_entries].bus.csi2.vc = i; + fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */ + + fd->num_entries++; + } + +out: + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + int ret; + + if (routing->num_routes == 0 || routing->num_routes > 2) + return -EINVAL; + + v4l2_subdev_lock_state(state); + + ret = _ox05b_set_routing(sd, state); + + v4l2_subdev_unlock_state(state); + + return ret; +} + +static int ox05b_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + int ret; + + ret = _ox05b_set_routing(sd, state); + + return ret; +} + +static int ox05b_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + code->code = ox05b_mbus_formats[code->index]; + + return 0; +} + +static int ox05b_enum_frame_sizes(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_size_enum *fse) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ox05b_mbus_formats); ++i) { + if (ox05b_mbus_formats[i] == fse->code) + break; + } + + if (i == ARRAY_SIZE(ox05b_mbus_formats)) + return -EINVAL; + + if (fse->index >= ARRAY_SIZE(ox05b_framesizes)) + return -EINVAL; + + fse->min_width = ox05b_framesizes[fse->index].width; + fse->max_width = fse->min_width; + fse->max_height = ox05b_framesizes[fse->index].height; + fse->min_height = fse->max_height; + + return 0; +} + +static int ox05b_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + fi->interval.numerator = 1; + fi->interval.denominator = ox05b->fps; + return 0; +} + +static int ox05b_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + struct ox05b *ox05b = to_ox05b(sd); + + dev_dbg(ox05b->dev, "%s: Set framerate %dfps\n", __func__, + fi->interval.denominator / fi->interval.numerator); + if ((fi->interval.denominator / fi->interval.numerator) != ox05b->fps) { + dev_err(ox05b->dev, "%s: Framerate can only be %dfps\n", + __func__, ox05b->fps); + return -EINVAL; + } + return 0; +} + +static int ox05b_detect(struct ox05b *ox05b) +{ + int ret; + u32 id; + + ret = ox05b_read(ox05b, OX05B_SC_CHIP_ID_HI, &id, 2); + if (ret < 0) + return ret; + + if (id != OX05B_CHIP_ID) { + dev_err(ox05b->dev, + "%s: unknown chip ID 0x%04x\n", __func__, id); + return -ENODEV; + } + + dev_info(ox05b->dev, "%s: detected chip ID 0x%04x\n", __func__, id); + return 0; +} + +static int ox05b_set_groupA(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->ir_exposure->val; + u32 again = ox05b->ir_again->val; + u32 dgain = ox05b->ir_dgain->val; + struct reg_sequence ox05b_groupA[] = { + {0x3208, 0x01}, /* Group 1 (IR Dominant VC0) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x01}, /* VC=1. This register takes effect from next frame. */ + {0x3208, 0x11}, /* Group 1 (IR Dominant VC0) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupA); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupA[i].reg, ox05b_groupA[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupA[i].reg, ox05b_groupA[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_groupB(struct ox05b *ox05b) +{ + int i, ret; + u32 exposure = ox05b->exposure->val; + u32 again = ox05b->again->val; + u32 dgain = ox05b->dgain->val; + struct reg_sequence ox05b_groupB[] = { + {0x3208, 0x00}, /* Group 0 (RGB Dominant VC1) hold start */ + {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */ + {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */ + {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */ + {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */ + {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */ + {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */ + {0x4813, 0x00}, /* VC=0. This register takes effect from next frame. */ + {0x3208, 0x10}, /* Group 0 (RGB Dominant VC1) hold end*/ + }; + + for (i = 0; i < ARRAY_SIZE(ox05b_groupB); i++) { + ret = regmap_write(ox05b->regmap, ox05b_groupB[i].reg, ox05b_groupB[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox05b_groupB[i].reg, ox05b_groupB[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_AB_mode_regs(struct ox05b *ox05b) +{ + int i, ret; + struct reg_sequence ox5b_AB_mode_regs[] = { + {0x3211, 0xF1}, /* AB mode enable */ + {0x3212, 0x21}, /* Enable sync between holds of group 0 and group 1*/ + {0x3208, 0xA0}, /* Always use for repeat launch */ + }; + + for (i = 0; i < ARRAY_SIZE(ox5b_AB_mode_regs); i++) { + ret = regmap_write(ox05b->regmap, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n", + __func__, i, ox5b_AB_mode_regs[i].reg, + ox5b_AB_mode_regs[i].def, ret); + return ret; + } + } + + return 0; +} + +static int ox05b_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ox05b *ox05b = container_of(ctrl->handler, struct ox05b, handler); + int ret; + + dev_dbg(ox05b->dev, "%s: %s, value: %d\n", __func__, + ctrl->name, ctrl->val); + + /* + * If the device is not powered up by the host driver do + * not apply any controls to H/W at this time. Instead + * the controls will be restored right after power-up. + */ + if (pm_runtime_suspended(ox05b->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + case V4L2_CID_ANALOGUE_GAIN: + case V4L2_CID_DIGITAL_GAIN: + ret = ox05b_set_groupB(ox05b); + break; + case V4L2_CID_IR_EXPOSURE: + case V4L2_CID_IR_ANALOGUE_GAIN: + case V4L2_CID_IR_DIGITAL_GAIN: + ret = ox05b_set_groupA(ox05b); + break; + case V4L2_CID_HFLIP: + case V4L2_CID_VFLIP: + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int ox05b_power_on(struct ox05b *ox05b) +{ + int ret; + + ret = clk_prepare_enable(ox05b->clk); + if (ret < 0) + return ret; + + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(100, 1000); + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 0); + msleep(30); + } + return 0; +} + +static int ox05b_power_off(struct ox05b *ox05b) +{ + if (ox05b->pwdn_gpio) { + gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1); + usleep_range(1, 10); + } + + clk_disable_unprepare(ox05b->clk); + + return 0; +} + +static int ox05b_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_on(ox05b); +} + +static int ox05b_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + return ox05b_power_off(ox05b); +} + +static int ox05b_start_stream(struct ox05b *ox05b) +{ + int ret; + + ret = ox05b_write_table(ox05b, ox05b_linear_2592x1944, + ARRAY_SIZE(ox05b_linear_2592x1944)); + if (ret < 0) + return ret; + + msleep(20); + + /* set registers for IR frame */ + ret = ox05b_set_groupA(ox05b); + if (ret < 0) + return ret; + + /* set registers for RGB frame */ + ret = ox05b_set_groupB(ox05b); + if (ret < 0) + return ret; + + /* set registers specific to AB mode */ + ret = ox05b_set_AB_mode_regs(ox05b); + + /* Set active */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0x01, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after exiting standby. + * we want the sensor to have sufficient time to process + * the new configurations. The same type of delays have been programmed + * in the OV2312 driver. + * TODO: check if there is a status register to poll for sensor readiness. + */ + msleep(20); + + return 0; +} + +static int ox05b_stop_stream(struct ox05b *ox05b) +{ + int ret; + + /* Set standby */ + ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0, 1); + if (ret < 0) + return ret; + + /* No communication is possible for a while after entering standby */ + usleep_range(10000, 20000); + return 0; +} + +static int ox05b_set_stream(struct v4l2_subdev *sd, int enable) +{ + struct ox05b *ox05b = to_ox05b(sd); + int ret; + + mutex_lock(&ox05b->lock); + if (ox05b->streaming == enable) { + mutex_unlock(&ox05b->lock); + return 0; + } + + if (enable) { + ret = pm_runtime_resume_and_get(ox05b->dev); + if (ret < 0) + goto err_unlock; + + ret = ox05b_start_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + + } else { + ret = ox05b_stop_stream(ox05b); + if (ret < 0) + goto err_runtime_put; + pm_runtime_put(ox05b->dev); + } + + ox05b->streaming = enable; + + mutex_unlock(&ox05b->lock); + return 0; + +err_runtime_put: + pm_runtime_put(ox05b->dev); + +err_unlock: + mutex_unlock(&ox05b->lock); + dev_err(ox05b->dev, + "%s: failed to setup streaming %d\n", __func__, ret); + return ret; +} + +static const struct v4l2_subdev_video_ops ox05b_subdev_video_ops = { + .g_frame_interval = ox05b_get_frame_interval, + .s_frame_interval = ox05b_set_frame_interval, + .s_stream = ox05b_set_stream, +}; + +static const struct v4l2_subdev_pad_ops ox05b_subdev_pad_ops = { + .init_cfg = ox05b_init_cfg, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ox05b_set_fmt, + .enum_mbus_code = ox05b_enum_mbus_code, + .enum_frame_size = ox05b_enum_frame_sizes, + .set_routing = ox05b_set_routing, + .get_frame_desc = ox05b_get_frame_desc, +}; + +static const struct v4l2_subdev_ops ox05b_subdev_ops = { + .video = &ox05b_subdev_video_ops, + .pad = &ox05b_subdev_pad_ops, +}; + +static const struct v4l2_ctrl_ops ox05b_ctrl_ops = { + .s_ctrl = ox05b_set_ctrl, +}; + +static const struct dev_pm_ops ox05b_pm_ops = { + SET_RUNTIME_PM_OPS(ox05b_suspend, ox05b_resume, NULL) +}; + +static int ox05b_probe(struct i2c_client *client) +{ + struct ox05b *ox05b; + struct v4l2_subdev *sd; + struct v4l2_ctrl_handler *ctrl_hdr; + int ret; + /* Allocate internal struct */ + ox05b = devm_kzalloc(&client->dev, sizeof(*ox05b), GFP_KERNEL); + if (!ox05b) + return -ENOMEM; + ox05b->dev = &client->dev; + + /* Initialize I2C Regmap */ + ox05b->regmap = devm_regmap_init_i2c(client, &ox05b_regmap_config); + if (IS_ERR(ox05b->regmap)) + return PTR_ERR(ox05b->regmap); + + /* Initialize Powerdown GPIO */ + ox05b->pwdn_gpio = devm_gpiod_get_optional(ox05b->dev, "pwdn", GPIOD_OUT_LOW); + if (IS_ERR(ox05b->pwdn_gpio)) + return PTR_ERR(ox05b->pwdn_gpio); + + ox05b->clk = devm_clk_get(ox05b->dev, "inck"); + if (IS_ERR(ox05b->clk)) + return PTR_ERR(ox05b->clk); + + ox05b->clk_rate = clk_get_rate(ox05b->clk); + + if (ox05b->clk_rate < 6000000 || ox05b->clk_rate > 27000000) + return -EINVAL; + + /* Power on */ + ret = ox05b_power_on(ox05b); + if (ret < 0) + return ret; + + /* Detect sensor */ + ret = ox05b_detect(ox05b); + if (ret < 0) + return ret; + + /* Initialize the subdev and its controls. */ + sd = &ox05b->subdev; + v4l2_i2c_subdev_init(sd, client, &ox05b_subdev_ops); + + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | + V4L2_SUBDEV_FL_HAS_EVENTS | + V4L2_SUBDEV_FL_STREAMS; + + /* Initialize the media entity. */ + ox05b->pad.flags = MEDIA_PAD_FL_SOURCE; + sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; + ret = media_entity_pads_init(&sd->entity, 1, &ox05b->pad); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: media entity init failed %d\n", __func__, ret); + return ret; + } + + ox05b->fps = OX05B_FRAMERATE_DEFAULT; + mutex_init(&ox05b->lock); + /* Initialize controls */ + ctrl_hdr = &ox05b->handler; + ret = v4l2_ctrl_handler_init(ctrl_hdr, 7); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: ctrl handler init failed: %d\n", __func__, ret); + goto err_media_cleanup; + } + + ox05b->handler.lock = &ox05b->lock; + + /* Add new controls */ + ox05b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ox05b_link_freq_menu) - 1, 0, + ox05b_link_freq_menu); + if (ox05b->link_freq) + ox05b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ox05b->exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + ox05b->dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + /* Added new control for IR frames. */ + ox05b->ir_exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_EXPOSURE, 0, + OX05B_EXPOSURE_MAX, + 1, OX05B_EXPOSURE_DEFAULT); + + ox05b->ir_again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_ANALOGUE_GAIN, 0, + OX05B_AGAIN_MAX, 1, + OX05B_AGAIN_DEFAULT); + + ox05b->ir_dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops, + V4L2_CID_IR_DIGITAL_GAIN, 0, + OX05B_DGAIN_MAX, 1, + OX05B_DGAIN_DEFAULT); + + ox05b->subdev.ctrl_handler = ctrl_hdr; + if (ox05b->handler.error) { + ret = ox05b->handler.error; + dev_err(ox05b->dev, + "%s: failed to add the ctrls: %d\n", __func__, ret); + goto err_ctrl_free; + } + + /* PM Runtime */ + pm_runtime_enable(ox05b->dev); + pm_runtime_set_suspended(ox05b->dev); + + ret = v4l2_subdev_init_finalize(sd); + if (ret < 0) { + dev_err(ox05b->dev, "%s: failed to init subdev: %d\n", __func__, ret); + goto err_pm_disable; + } + + /* Finally, register the subdev. */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_err(ox05b->dev, + "%s: v4l2 subdev register failed %d\n", __func__, ret); + goto err_subdev_cleanup; + } + + dev_info(ox05b->dev, "ox05b1s probed!\n"); + return 0; + +err_subdev_cleanup: + v4l2_subdev_cleanup(&ox05b->subdev); + +err_pm_disable: + pm_runtime_disable(ox05b->dev); + +err_ctrl_free: + v4l2_ctrl_handler_free(ctrl_hdr); + mutex_destroy(&ox05b->lock); + +err_media_cleanup: + media_entity_cleanup(&ox05b->subdev.entity); + + return ret; +} + +static void ox05b_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ox05b *ox05b = to_ox05b(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_ctrl_handler_free(&ox05b->handler); + v4l2_subdev_cleanup(&ox05b->subdev); + media_entity_cleanup(&sd->entity); + mutex_destroy(&ox05b->lock); + + pm_runtime_disable(ox05b->dev); +} + +static const struct of_device_id ox05b_of_match[] = { + { .compatible = "ovti,ox05b" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, ox05b_of_match); + +static struct i2c_driver ox05b_i2c_driver = { + .driver = { + .name = "ox05b", + .of_match_table = ox05b_of_match, + .pm = &ox05b_pm_ops, + }, + .probe_new = ox05b_probe, + .remove = ox05b_remove, +}; + +module_i2c_driver(ox05b_i2c_driver); + +MODULE_AUTHOR("Abhishek Sharma "); +MODULE_DESCRIPTION("OX05B1S RGB-IR Image Sensor driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 390df90762fb5d3f9deb029224c9015ce9ce21c1 Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Thu, 14 Mar 2024 16:55:42 +0530 Subject: arm64: defconfig: Enable OX05B1S driver As of now, only AM62A supports the OX05B1S sensor. The sensor module can be connected to a single CSI port on AM62A. Enable the driver for OX05B1S. Signed-off-by: Abhishek Sharma --- arch/arm64/configs/defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig index e6627a10a4ff..c59d34af15a7 100644 --- a/arch/arm64/configs/defconfig +++ b/arch/arm64/configs/defconfig @@ -789,6 +789,7 @@ CONFIG_VIDEO_IMX390=m CONFIG_VIDEO_OV2312=m CONFIG_VIDEO_OV5640=m CONFIG_VIDEO_OV5645=m +CONFIG_VIDEO_OX05B1S=m CONFIG_VIDEO_DS90UB953=m CONFIG_VIDEO_DS90UB960=m CONFIG_DRM=m -- cgit v1.2.3 From 3cfe68e02aa4a3059f84bb21d07330377f273edd Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Thu, 14 Mar 2024 16:55:43 +0530 Subject: arm64: boot: dts: ti: k3-am62a7: Overlay for LI OX05B1S OX05B1S is a raw (4x4 RGB-IR bayer) sensor. The LI-OX05B1S-MIPI-137H module [1] uses a LI-FPC22-IPEX-PI [2] adapter cable for connection with CSI port on the board. [1] Link: https://www.mouser.com/ProductDetail/Leopard-Imaging/ LI-OX05B1S-MIPI-137H?qs=VJzv269c%252BPbBVMoFtZszhQ%3D%3D [2] Link: https://www.leopardimaging.com/product/nvidia-jetson-cameras/ nvidia-jetson-orin-nx-camera-kit/li-fpc22-ipex-pi/ Signed-off-by: Abhishek Sharma --- arch/arm64/boot/dts/ti/Makefile | 1 + .../boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso | 68 ++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile index abc4b5a4352e..808d649ec243 100644 --- a/arch/arm64/boot/dts/ti/Makefile +++ b/arch/arm64/boot/dts/ti/Makefile @@ -39,6 +39,7 @@ k3-am62a7-sk-ub954-evm-ov2312-dtbs := k3-am62a7-sk.dtb \ k3-am62a7-sk-ub954-evm.dtbo \ k3-fpdlink-ov2312-0-0.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-imx219.dtb +dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-ox05b1s.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-e3-max-opp.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-ethernet-dc01.dtbo dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-fusion-imx390.dtb diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso new file mode 100644 index 000000000000..e82589579013 --- /dev/null +++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * OX05B1S Camera Module + * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/ + */ + +/dts-v1/; +/plugin/; + +#include + +&{/} { + clk_ox05b1s_fixed: ox05b1s-xclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; +}; + +&main_i2c2 { + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + i2c-switch@71 { + compatible = "nxp,pca9543"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x71>; + + /* CAM port */ + i2c@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + link-frequencies = /bits/ 64 <480000000>; + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; + }; + }; + }; + }; +}; + +&csi0_port0 { + status = "okay"; + + csi2rx0_in_sensor: endpoint { + remote-endpoint = <&csi2_cam0>; + bus-type = <4>; /* CSI2 DPHY. */ + clock-lanes = <0>; + data-lanes = <1 2 3 4>; + }; +}; -- cgit v1.2.3 From 141653a4968ab356a63bf9da280aa607501b356d Mon Sep 17 00:00:00 2001 From: Abhishek Sharma Date: Thu, 14 Mar 2024 16:55:44 +0530 Subject: dt-bindings: media: i2c: ovti,ox05b: add OX05B1S sensor Add OX05B1S device tree bindings. Signed-off-by: Abhishek Sharma --- .../devicetree/bindings/media/i2c/ovti,ox05b.yaml | 87 ++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml new file mode 100644 index 000000000000..f84ccd4d5d91 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/i2c/ovti,ox05b.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: OmniVision OX05B1S Camera Sensor + +maintainers: + - Abhishek Sharma + +description: |- + Omnivision OX05B1S is an RGBIR camera sensor with an active array size of + 2592x1944. It is programmable through the I2C interface. The i2c client + address is fixed at 0x36 as per the sensor datasheet. Every alternate frame, + the sensor changes the exposure/gain registers to stream an - + A. IR-dominant frame on CSI-2 virtual channel 0 + B. RGB-dominant frame on CSI-2 virtual channel 1 + + Both streams are captured at a resolution 2592x1944, 30 fps each + (60 fps total). The sensor also supports a few v4l2 controls like + exposure and gain controls. + +properties: + compatible: + enum: + - ovti,ox05b + + reg: + description: I2C address + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: inck + + pwdn-gpios: + maxItems: 1 + description: + Specifier for the GPIO connected to the PWDN pin. + + port: + $ref: /schemas/graph.yaml#/properties/port + additionalProperties: false + + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + +required: + - compatible + - reg + - clocks + - clock-names + - port + +additionalProperties: false + +examples: + - | + #include + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + ox05b1s: camera@36 { + compatible = "ovti,ox05b"; + reg = <0x36>; + + clocks = <&clk_ox05b1s_fixed>; + clock-names = "inck"; + + pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>; + + port { + csi2_cam0: endpoint { + remote-endpoint = <&csi2rx0_in_sensor>; + }; + }; + }; + }; + +... -- cgit v1.2.3 From 1c154b1fe4c462d8b383515bb388e289816e4b01 Mon Sep 17 00:00:00 2001 From: Chintan Vankar Date: Thu, 14 Mar 2024 17:24:12 +0530 Subject: net: ethernet: ti: am65-cpsw/cpts: Add workaround for errata i2401 The CPSW Ethernet Switch on TI's K3 SoCs supports two mechanisms to timestamp packets received on external ports. The first mechanism which is currently enabled by the am65-cpsw-nuss driver is that of timestamping all received packets by setting the "TSTAMP_EN" bit in the CPTS_CONTROL register, which directs the CPTS module to timestamp all received packets, followed by passing the timestamps via the DMA descriptors. This mechanism is responsible for triggering errata i2401: "CPSW: Host Timestamps Cause CPSW Port to Lock up" The workaround is to use the second mechanism for timestamping received packets. The second mechanism utilizes the CPTS Event FIFO that records timestamps corresponding to certain events, with one such event being the reception of an Ethernet packet with the EtherType field set to Precision Time Protocol (PTP). Hence, switch to the second mechanism to address the errata. The errata affects all K3 SoCs. Link to errata for AM64x: https://www.ti.com/lit/er/sprz457h/sprz457h.pdf Fixes: b1f66a5bee07 ("net: ethernet: ti: am65-cpsw-nuss: enable packet timestamping support") Signed-off-by: Chintan Vankar Reviewed-by: Ravi Gunasekaran --- drivers/net/ethernet/ti/am65-cpsw-nuss.c | 48 ++++++++---------- drivers/net/ethernet/ti/am65-cpts.c | 85 +++++++++++++++++++++++--------- drivers/net/ethernet/ti/am65-cpts.h | 11 +++-- 3 files changed, 89 insertions(+), 55 deletions(-) diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c index cf76bade4ace..684c6e120e1c 100644 --- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c +++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c @@ -92,10 +92,14 @@ #define AM65_CPSW_PORT_REG_PRI_CTL_RX_PTYPE_RROBIN BIT(8) /* AM65_CPSW_PN_TS_CTL register fields */ +#define AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN BIT(0) +#define AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN BIT(1) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN BIT(3) #define AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN BIT(4) #define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN BIT(5) #define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT2_EN BIT(6) #define AM65_CPSW_PN_TS_CTL_TX_ANX_D_EN BIT(7) +#define AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN BIT(9) #define AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN BIT(10) #define AM65_CPSW_PN_TS_CTL_TX_HOST_TS_EN BIT(11) #define AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT 16 @@ -123,6 +127,11 @@ AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN | \ AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN) +#define AM65_CPSW_TS_RX_ANX_ALL_EN \ + (AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN | \ + AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN) + #define AM65_CPSW_ALE_AGEOUT_DEFAULT 30 /* Number of TX/RX descriptors */ #define AM65_CPSW_MAX_TX_DESC 500 @@ -677,18 +686,6 @@ static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma) dev_kfree_skb_any(skb); } -static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata) -{ - struct skb_shared_hwtstamps *ssh; - u64 ns; - - ns = ((u64)psdata[1] << 32) | psdata[0]; - - ssh = skb_hwtstamps(skb); - memset(ssh, 0, sizeof(*ssh)); - ssh->hwtstamp = ns_to_ktime(ns); -} - /* RX psdata[2] word format - checksum information */ #define AM65_CPSW_RX_PSD_CSUM_ADD GENMASK(15, 0) #define AM65_CPSW_RX_PSD_CSUM_ERR BIT(16) @@ -769,9 +766,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, skb->dev = ndev; psdata = cppi5_hdesc_get_psdata(desc_rx); - /* add RX timestamp */ - if (port->rx_ts_enabled) - am65_cpsw_nuss_rx_ts(skb, psdata); csum_info = psdata[2]; dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info); @@ -784,6 +778,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common, ndev_priv = netdev_priv(ndev); am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark); skb_put(skb, pkt_len); + if (port->rx_ts_enabled) + am65_cpts_rx_timestamp(common->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); am65_cpsw_nuss_rx_csum(skb, csum_info); napi_gro_receive(&common->napi_rx, skb); @@ -1312,7 +1308,6 @@ static int am65_cpsw_nuss_ndo_slave_set_mac_address(struct net_device *ndev, static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, struct ifreq *ifr) { - struct am65_cpsw_common *common = am65_ndev_to_common(ndev); struct am65_cpsw_port *port = am65_ndev_to_port(ndev); u32 ts_ctrl, seq_id, ts_ctrl_ltype2, ts_vlan_ltype; struct hwtstamp_config cfg; @@ -1336,11 +1331,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, case HWTSTAMP_FILTER_NONE: port->rx_ts_enabled = false; break; - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_SOME: - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: @@ -1350,10 +1340,13 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - case HWTSTAMP_FILTER_NTP_ALL: port->rx_ts_enabled = true; - cfg.rx_filter = HWTSTAMP_FILTER_ALL; + cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; break; + case HWTSTAMP_FILTER_ALL: + case HWTSTAMP_FILTER_SOME: + case HWTSTAMP_FILTER_NTP_ALL: + return -EOPNOTSUPP; default: return -ERANGE; } @@ -1383,6 +1376,10 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN | AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN; + if (port->rx_ts_enabled) + ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN | + AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN; + writel(seq_id, port->port_base + AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG); writel(ts_vlan_ltype, port->port_base + AM65_CPSW_PORTN_REG_TS_VLAN_LTYPE_REG); @@ -1390,9 +1387,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev, AM65_CPSW_PORTN_REG_TS_CTL_LTYPE2); writel(ts_ctrl, port->port_base + AM65_CPSW_PORTN_REG_TS_CTL); - /* en/dis RX timestamp */ - am65_cpts_rx_enable(common->cpts, port->rx_ts_enabled); - return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } @@ -1409,7 +1403,7 @@ static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev, cfg.tx_type = port->tx_ts_enabled ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF; cfg.rx_filter = port->rx_ts_enabled ? - HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE; + HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE; return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; } diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c index c66618d91c28..29e0b9ff23bf 100644 --- a/drivers/net/ethernet/ti/am65-cpts.c +++ b/drivers/net/ethernet/ti/am65-cpts.c @@ -859,29 +859,6 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp) return delay; } -/** - * am65_cpts_rx_enable - enable rx timestamping - * @cpts: cpts handle - * @en: enable - * - * This functions enables rx packets timestamping. The CPTS can timestamp all - * rx packets. - */ -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) -{ - u32 val; - - mutex_lock(&cpts->ptp_clk_lock); - val = am65_cpts_read32(cpts, control); - if (en) - val |= AM65_CPTS_CONTROL_TSTAMP_EN; - else - val &= ~AM65_CPTS_CONTROL_TSTAMP_EN; - am65_cpts_write32(cpts, val, control); - mutex_unlock(&cpts->ptp_clk_lock); -} -EXPORT_SYMBOL_GPL(am65_cpts_rx_enable); - static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid) { unsigned int ptp_class = ptp_classify_raw(skb); @@ -906,6 +883,68 @@ static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid) return 1; } +static u64 am65_cpts_get_rx_ts(struct am65_cpts *cpts, struct sk_buff *skb, + u32 skb_mtype_seqid) +{ + struct list_head *this, *next; + struct am65_cpts_event *event; + unsigned long flags; + u32 mtype_seqid; + u64 ns = 0; + + am65_cpts_fifo_read(cpts); + spin_lock_irqsave(&cpts->lock, flags); + list_for_each_safe(this, next, &cpts->events) { + event = list_entry(this, struct am65_cpts_event, list); + if (time_after(jiffies, event->tmo)) { + list_del_init(&event->list); + list_add(&event->list, &cpts->pool); + continue; + } + + mtype_seqid = event->event1 & + (AM65_CPTS_EVENT_1_MESSAGE_TYPE_MASK | + AM65_CPTS_EVENT_1_SEQUENCE_ID_MASK | + AM65_CPTS_EVENT_1_EVENT_TYPE_MASK); + + if (mtype_seqid == skb_mtype_seqid) { + ns = event->timestamp; + list_del_init(&event->list); + list_add(&event->list, &cpts->pool); + break; + } + } + spin_unlock_irqrestore(&cpts->lock, flags); + + return ns; +} + +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) +{ + struct am65_cpts_skb_cb_data *skb_cb = (struct am65_cpts_skb_cb_data *)skb->cb; + struct skb_shared_hwtstamps *ssh; + int ret; + u64 ns; + + skb_reset_mac_header(skb); + ret = am65_skb_get_mtype_seqid(skb, &skb_cb->skb_mtype_seqid); + if (!ret) + return; /* if not PTP class packet */ + + skb_cb->skb_mtype_seqid |= (AM65_CPTS_EV_RX << AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT); + + dev_dbg(cpts->dev, "%s mtype seqid %08x\n", __func__, skb_cb->skb_mtype_seqid); + + ns = am65_cpts_get_rx_ts(cpts, skb, skb_cb->skb_mtype_seqid); + if (!ns) + return; + + ssh = skb_hwtstamps(skb); + memset(ssh, 0, sizeof(*ssh)); + ssh->hwtstamp = ns_to_ktime(ns); +} +EXPORT_SYMBOL_GPL(am65_cpts_rx_timestamp); + /** * am65_cpts_tx_timestamp - save tx packet for timestamping * @cpts: cpts handle diff --git a/drivers/net/ethernet/ti/am65-cpts.h b/drivers/net/ethernet/ti/am65-cpts.h index 6e14df0be113..6099d772799d 100644 --- a/drivers/net/ethernet/ti/am65-cpts.h +++ b/drivers/net/ethernet/ti/am65-cpts.h @@ -22,9 +22,9 @@ void am65_cpts_release(struct am65_cpts *cpts); struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs, struct device_node *node); int am65_cpts_phc_index(struct am65_cpts *cpts); +void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb); -void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en); u64 am65_cpts_ns_gettime(struct am65_cpts *cpts); int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx, struct am65_cpts_estf_cfg *cfg); @@ -48,17 +48,18 @@ static inline int am65_cpts_phc_index(struct am65_cpts *cpts) return -1; } -static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, +static inline void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb) { } -static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, - struct sk_buff *skb) +static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } -static inline void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en) +static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, + struct sk_buff *skb) { } -- cgit v1.2.3