* Re: [PATCH v6 09/15] media: bcm2835-unicam: Add support for CCP2/CSI2 camera interface
From: Laurent Pinchart @ 2024-03-26 1:37 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, Dave Stevenson, David Plowman, Jean-Michel Hautbois,
Hans Verkuil, Naushir Patuck, kernel-list, linux-rpi-kernel,
Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, devicetree
In-Reply-To: <ZgHEQTHZlRr_Rz6K@kekkonen.localdomain>
Hi Sakari,
On Mon, Mar 25, 2024 at 06:36:49PM +0000, Sakari Ailus wrote:
> On Fri, Mar 01, 2024 at 11:32:24PM +0200, Laurent Pinchart wrote:
> > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> >
> > Add a driver for the Unicam camera receiver block on BCM283x processors.
> > It is represented as two video device nodes: unicam-image and
> > unicam-embedded which are connected to an internal subdev (named
> > unicam-subdev) in order to manage streams routing.
> >
> > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > Co-developed-by: Naushir Patuck <naush@raspberrypi.com>
> > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > Co-developed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
>
> Thanks for submitting this, it's the cleanest and neatest Unicom driver
Unicam, or if you insist Unicorn, but not Unicom :-)
> I've ever seen!
>
> Some mostly unimportant comments below, however the bus-type issue needs to
> be addressed.
>
> > ---
> > Changes since v5:
> >
> > - Move to drivers/media/platform/broadcom/
> > - Port to the upstream V4L2 streams API
> > - Rebase on latest metadata API proposal
> > - Add missing error message
> > - Drop unneeded documentation block for unicam_isr()
> > - Drop unneeded dev_dbg() and dev_err() messages
> > - Drop unneeded streams_mask and fmt checks
> > - Drop unused unicam_sd_pad_is_sink()
> > - Drop unneeded includes
> > - Drop v4l2_ctrl_subscribe_event() call
> > - Use pm_runtime_resume_and_get()
> > - Indentation and line wrap fixes
> > - Let the framework set bus_info
> > - Use v4l2_fwnode_endpoint_parse()
> > - Fix media device cleanup
> > - Drop lane reordering checks
> > - Fix subdev state locking
> > - Drop extra debug messages
> > - Move clock handling to runtime PM handlers
> > - Reorder functions
> > - Rename init functions for more clarity
> > - Initialize runtime PM earlier
> > - Clarify error messages
> > - Simplify subdev init with local variable
> > - Fix subdev cleanup
> > - Fix typos and indentation
> > - Don't initialize local variables needlessly
> > - Simplify num lanes check
> > - Fix metadata handling in subdev set_fmt
> > - Drop manual fallback to .s_stream()
> > - Pass v4l2_pix_format to unicam_calc_format_size_bpl()
> > - Simplify unicam_set_default_format()
> > - Fix default format settings
> > - Add busy check in unicam_s_fmt_meta()
> > - Add missing \n at end of format strings
> > - Fix metadata handling in subdev set_fmt
> > - Fix locking when starting streaming
> > - Return buffers from start streaming fails
> > - Fix format validation for metadata node
> > - Use video_device_pipeline_{start,stop}() helpers
> > - Simplify format enumeration
> > - Drop unset variable
> > - Update MAINTAINERS entry
> > - Update to the upstream v4l2_async_nf API
> > - Update to the latest subdev routing API
> > - Update to the latest subdev state API
> > - Move from subdev .init_cfg() to .init_state()
> > - Update to the latest videobuf2 API
> > - Fix v4l2_subdev_enable_streams() error check
> > - Use correct pad for the connected subdev
> > - Return buffers to vb2 when start streaming fails
> > - Improve debugging in start streaming handler
> > - Simplify DMA address management
> > - Drop comment about bcm2835-camera driver
> > - Clarify comments that explain min/max sizes
> > - Pass v4l2_pix_format to unicam_try_fmt()
> > - Drop unneeded local variables
> > - Rename image-related constants and functions
> > - Turn unicam_fmt.metadata_fmt into bool
> > - Rename unicam_fmt to unicam_format_info
> > - Rename unicam_format_info variables to fmtinfo
> > - Rename unicam_node.v_fmt to fmt
> > - Add metadata formats for RAW10, RAW12 and RAW14
> > - Make metadata formats line-based
> > - Validate format on metadata video device
> > - Add Co-devlopped-by tags
> >
> > Changes since v3:
> >
> > - Add the vendor prefix for DT name
> > - Use the reg-names in DT parsing
> > - Remove MAINTAINERS entry
> >
> > Changes since v2:
> >
> > - Change code organization
> > - Remove unused variables
> > - Correct the fmt_meta functions
> > - Rewrite the start/stop streaming
> > - You can now start the image node alone, but not the metadata one
> > - The buffers are allocated per-node
> > - only the required stream is started, if the route exists and is
> > enabled
> > - Prefix the macros with UNICAM_ to not have too generic names
> > - Drop colorspace support
> >
> > Changes since v1:
> >
> > - Replace the unicam_{info,debug,error} macros with dev_*()
> > ---
> > MAINTAINERS | 1 +
> > drivers/media/platform/Kconfig | 1 +
> > drivers/media/platform/Makefile | 1 +
> > drivers/media/platform/broadcom/Kconfig | 23 +
> > drivers/media/platform/broadcom/Makefile | 3 +
> > .../platform/broadcom/bcm2835-unicam-regs.h | 255 ++
> > .../media/platform/broadcom/bcm2835-unicam.c | 2607 +++++++++++++++++
> > 7 files changed, 2891 insertions(+)
> > create mode 100644 drivers/media/platform/broadcom/Kconfig
> > create mode 100644 drivers/media/platform/broadcom/Makefile
> > create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam.c
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index e50a59654e6e..cc350729f467 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -4002,6 +4002,7 @@ M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
> > L: linux-media@vger.kernel.org
> > S: Maintained
> > F: Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml
> > +F: drivers/media/platform/bcm2835/
> >
> > BROADCOM BCM47XX MIPS ARCHITECTURE
> > M: Hauke Mehrtens <hauke@hauke-m.de>
> > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > index 91e54215de3a..2d79bfc68c15 100644
> > --- a/drivers/media/platform/Kconfig
> > +++ b/drivers/media/platform/Kconfig
> > @@ -67,6 +67,7 @@ source "drivers/media/platform/amlogic/Kconfig"
> > source "drivers/media/platform/amphion/Kconfig"
> > source "drivers/media/platform/aspeed/Kconfig"
> > source "drivers/media/platform/atmel/Kconfig"
> > +source "drivers/media/platform/broadcom/Kconfig"
> > source "drivers/media/platform/cadence/Kconfig"
> > source "drivers/media/platform/chips-media/Kconfig"
> > source "drivers/media/platform/intel/Kconfig"
> > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > index 3296ec1ebe16..da17301f7439 100644
> > --- a/drivers/media/platform/Makefile
> > +++ b/drivers/media/platform/Makefile
> > @@ -10,6 +10,7 @@ obj-y += amlogic/
> > obj-y += amphion/
> > obj-y += aspeed/
> > obj-y += atmel/
> > +obj-y += broadcom/
> > obj-y += cadence/
> > obj-y += chips-media/
> > obj-y += intel/
> > diff --git a/drivers/media/platform/broadcom/Kconfig b/drivers/media/platform/broadcom/Kconfig
> > new file mode 100644
> > index 000000000000..cc2c9afcc948
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/Kconfig
> > @@ -0,0 +1,23 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +config VIDEO_BCM2835_UNICAM
> > + tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
> > + depends on ARCH_BCM2835 || COMPILE_TEST
> > + depends on PM
> > + depends on VIDEO_DEV
> > + select MEDIA_CONTROLLER
> > + select V4L2_FWNODE
> > + select VIDEO_V4L2_SUBDEV_API
> > + select VIDEOBUF2_DMA_CONTIG
> > + help
> > + Say Y here to enable support for the BCM283x/BCM271x CSI-2 receiver.
> > + This is a V4L2 driver that controls the CSI-2 receiver directly,
> > + independently from the VC4 firmware.
> > +
> > + This driver is mutually exclusive with the use of bcm2835-camera. The
> > + firmware will disable all access to the peripheral from within the
> > + firmware if it finds a DT node using it, and bcm2835-camera will
> > + therefore fail to probe.
> > +
> > + To compile this driver as a module, choose M here. The module will be
> > + called bcm2835-unicam.
> > diff --git a/drivers/media/platform/broadcom/Makefile b/drivers/media/platform/broadcom/Makefile
> > new file mode 100644
> > index 000000000000..03d2045aba2e
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/Makefile
> > @@ -0,0 +1,3 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +
> > +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
> > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam-regs.h b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > new file mode 100644
> > index 000000000000..84775fd2fac5
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > @@ -0,0 +1,255 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +
> > +/*
> > + * Copyright (C) 2017-2020 Raspberry Pi Trading.
>
> Anything up to 2024?
Not really. The registers haven't really changed :-) I'll update the
copyright in the .c file though.
> > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > + */
[snip]
> > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > new file mode 100644
> > index 000000000000..716c89b8a217
> > --- /dev/null
> > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > @@ -0,0 +1,2607 @@
[snip]
> > +static irqreturn_t unicam_isr(int irq, void *dev)
> > +{
> > + struct unicam_device *unicam = dev;
> > + unsigned int lines_done = unicam_get_lines_done(dev);
> > + unsigned int sequence = unicam->sequence;
> > + unsigned int i;
> > + u32 ista, sta;
> > + bool fe;
> > + u64 ts;
> > +
> > + sta = unicam_reg_read(unicam, UNICAM_STA);
> > + /* Write value back to clear the interrupts */
> > + unicam_reg_write(unicam, UNICAM_STA, sta);
> > +
> > + ista = unicam_reg_read(unicam, UNICAM_ISTA);
> > + /* Write value back to clear the interrupts */
> > + unicam_reg_write(unicam, UNICAM_ISTA, ista);
> > +
> > + dev_dbg(unicam->dev, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d\n",
> > + ista, sta, sequence, lines_done);
> > +
> > + if (!(sta & (UNICAM_IS | UNICAM_PI0)))
> > + return IRQ_HANDLED;
> > +
> > + /*
> > + * Look for either the Frame End interrupt or the Packet Capture status
> > + * to signal a frame end.
> > + */
> > + fe = ista & UNICAM_FEI || sta & UNICAM_PI0;
> > +
> > + /*
> > + * We must run the frame end handler first. If we have a valid next_frm
> > + * and we get a simultaneout FE + FS interrupt, running the FS handler
> > + * first would null out the next_frm ptr and we would have lost the
> > + * buffer forever.
> > + */
> > + if (fe) {
> > + /*
> > + * Ensure we have swapped buffers already as we can't
> > + * stop the peripheral. If no buffer is available, use a
> > + * dummy buffer to dump out frames until we get a new buffer
> > + * to use.
> > + */
> > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > + if (!unicam->node[i].streaming)
> > + continue;
> > +
> > + /*
> > + * If cur_frm == next_frm, it means we have not had
> > + * a chance to swap buffers, likely due to having
> > + * multiple interrupts occurring simultaneously (like FE
> > + * + FS + LS). In this case, we cannot signal the buffer
> > + * as complete, as the HW will reuse that buffer.
> > + */
> > + if (unicam->node[i].cur_frm &&
> > + unicam->node[i].cur_frm != unicam->node[i].next_frm)
> > + unicam_process_buffer_complete(&unicam->node[i],
> > + sequence);
> > + unicam->node[i].cur_frm = unicam->node[i].next_frm;
> > + }
> > + unicam->sequence++;
>
> Does access to this data need to be serialised somehow.
Given that it's only accessed from the interrupt handler (beside
start_streaming time, before starting the hardware), I don't think so.
> > + }
> > +
> > + if (ista & UNICAM_FSI) {
> > + /*
> > + * Timestamp is to be when the first data byte was captured,
> > + * aka frame start.
> > + */
> > + ts = ktime_get_ns();
> > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > + if (!unicam->node[i].streaming)
> > + continue;
> > +
> > + if (unicam->node[i].cur_frm)
> > + unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
> > + ts;
> > + else
> > + dev_dbg(unicam->v4l2_dev.dev,
> > + "ISR: [%d] Dropping frame, buffer not available at FS\n",
> > + i);
> > + /*
> > + * Set the next frame output to go to a dummy frame
> > + * if we have not managed to obtain another frame
> > + * from the queue.
> > + */
> > + unicam_schedule_dummy_buffer(&unicam->node[i]);
> > + }
> > +
> > + unicam_queue_event_sof(unicam);
> > + }
> > +
> > + /*
> > + * Cannot swap buffer at frame end, there may be a race condition
> > + * where the HW does not actually swap it if the new frame has
> > + * already started.
> > + */
> > + if (ista & (UNICAM_FSI | UNICAM_LCI) && !fe) {
> > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > + if (!unicam->node[i].streaming)
> > + continue;
> > +
> > + spin_lock(&unicam->node[i].dma_queue_lock);
> > + if (!list_empty(&unicam->node[i].dma_queue) &&
> > + !unicam->node[i].next_frm)
> > + unicam_schedule_next_buffer(&unicam->node[i]);
> > + spin_unlock(&unicam->node[i].dma_queue_lock);
> > + }
> > + }
> > +
> > + if (unicam_reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
> > + /* Switch out of trigger mode if selected */
> > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > + unicam_reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
> > + }
> > + return IRQ_HANDLED;
> > +}
> > +
> > +static void unicam_set_packing_config(struct unicam_device *unicam)
> > +{
> > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > + u32 pack, unpack;
> > + u32 val;
> > +
> > + if (node->fmt.fmt.pix.pixelformat == node->fmtinfo->fourcc) {
> > + unpack = UNICAM_PUM_NONE;
> > + pack = UNICAM_PPM_NONE;
> > + } else {
> > + switch (node->fmtinfo->depth) {
> > + case 8:
> > + unpack = UNICAM_PUM_UNPACK8;
> > + break;
> > + case 10:
> > + unpack = UNICAM_PUM_UNPACK10;
> > + break;
> > + case 12:
> > + unpack = UNICAM_PUM_UNPACK12;
> > + break;
> > + case 14:
> > + unpack = UNICAM_PUM_UNPACK14;
> > + break;
> > + case 16:
> > + unpack = UNICAM_PUM_UNPACK16;
> > + break;
> > + default:
> > + unpack = UNICAM_PUM_NONE;
> > + break;
> > + }
> > +
> > + /* Repacking is always to 16bpp */
> > + pack = UNICAM_PPM_PACK16;
>
> Also 8-bit data?
Not that I know of. The 8-bit entries in unicam_image_formats have no
.unpacked_fourcc field, so the condition in the if above will always be
true for those as they can only be selected by setting the pixel format
to fmtinfo->fourcc.
> > + }
> > +
> > + val = 0;
>
> You could do initialisation in declaration.
Yes, but I think it's more readable to keep all the code that affects
the 'val' variable together.
> > + unicam_set_field(&val, unpack, UNICAM_PUM_MASK);
> > + unicam_set_field(&val, pack, UNICAM_PPM_MASK);
> > + unicam_reg_write(unicam, UNICAM_IPIPE, val);
> > +}
> > +
> > +static void unicam_cfg_image_id(struct unicam_device *unicam)
> > +{
> > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > +
> > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > + /* CSI2 mode, hardcode VC 0 for now. */
> > + unicam_reg_write(unicam, UNICAM_IDI0,
> > + (0 << 6) | node->fmtinfo->csi_dt);
> > + } else {
> > + /* CCP2 mode */
> > + unicam_reg_write(unicam, UNICAM_IDI0,
> > + 0x80 | node->fmtinfo->csi_dt);
> > + }
> > +}
> > +
> > +static void unicam_enable_ed(struct unicam_device *unicam)
> > +{
> > + u32 val = unicam_reg_read(unicam, UNICAM_DCS);
> > +
> > + unicam_set_field(&val, 2, UNICAM_EDL_MASK);
> > + /* Do not wrap at the end of the embedded data buffer */
> > + unicam_set_field(&val, 0, UNICAM_DBOB);
> > +
> > + unicam_reg_write(unicam, UNICAM_DCS, val);
> > +}
> > +
> > +static void unicam_start_rx(struct unicam_device *unicam,
> > + struct unicam_buffer *buf)
> > +{
> > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > + int line_int_freq = node->fmt.fmt.pix.height >> 2;
> > + unsigned int i;
> > + u32 val;
> > +
> > + if (line_int_freq < 128)
> > + line_int_freq = 128;
>
> line_int_freq = max(line_int_freq, 128);
Ack.
> > +
> > + /* Enable lane clocks */
> > + val = 1;
>
> Initialise in the loop initialisation below, I'd say.
How about
val = 0x55 & GENMASK(unicam->pipe.num_data_lanes * 2 - 1, 0);
?
> > + for (i = 0; i < unicam->active_data_lanes; i++)
> > + val = val << 2 | 1;
> > + unicam_clk_write(unicam, val);
> > +
> > + /* Basic init */
> > + unicam_reg_write(unicam, UNICAM_CTRL, UNICAM_MEM);
> > +
> > + /* Enable analogue control, and leave in reset. */
> > + val = UNICAM_AR;
> > + unicam_set_field(&val, 7, UNICAM_CTATADJ_MASK);
> > + unicam_set_field(&val, 7, UNICAM_PTATADJ_MASK);
> > + unicam_reg_write(unicam, UNICAM_ANA, val);
> > + usleep_range(1000, 2000);
> > +
> > + /* Come out of reset */
> > + unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_AR);
> > +
> > + /* Peripheral reset */
> > + unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPR);
> > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPR);
> > +
> > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPE);
> > +
> > + /* Enable Rx control. */
> > + val = unicam_reg_read(unicam, UNICAM_CTRL);
> > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > + unicam_set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
> > + unicam_set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
> > + } else {
> > + unicam_set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
> > + unicam_set_field(&val, unicam->bus_flags, UNICAM_DCM_MASK);
> > + }
> > + /* Packet framer timeout */
> > + unicam_set_field(&val, 0xf, UNICAM_PFT_MASK);
> > + unicam_set_field(&val, 128, UNICAM_OET_MASK);
> > + unicam_reg_write(unicam, UNICAM_CTRL, val);
> > +
> > + unicam_reg_write(unicam, UNICAM_IHWIN, 0);
> > + unicam_reg_write(unicam, UNICAM_IVWIN, 0);
> > +
> > + /* AXI bus access QoS setup */
> > + val = unicam_reg_read(unicam, UNICAM_PRI);
> > + unicam_set_field(&val, 0, UNICAM_BL_MASK);
> > + unicam_set_field(&val, 0, UNICAM_BS_MASK);
> > + unicam_set_field(&val, 0xe, UNICAM_PP_MASK);
> > + unicam_set_field(&val, 8, UNICAM_NP_MASK);
> > + unicam_set_field(&val, 2, UNICAM_PT_MASK);
> > + unicam_set_field(&val, 1, UNICAM_PE);
> > + unicam_reg_write(unicam, UNICAM_PRI, val);
> > +
> > + unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_DDL);
> > +
> > + /* Always start in trigger frame capture mode (UNICAM_FCM set) */
> > + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
> > + unicam_set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
> > + unicam_reg_write(unicam, UNICAM_ICTL, val);
> > + unicam_reg_write(unicam, UNICAM_STA, UNICAM_STA_MASK_ALL);
> > + unicam_reg_write(unicam, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
> > +
> > + /* tclk_term_en */
> > + unicam_reg_write_field(unicam, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
> > + /* tclk_settle */
> > + unicam_reg_write_field(unicam, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
> > + /* td_term_en */
> > + unicam_reg_write_field(unicam, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
> > + /* ths_settle */
> > + unicam_reg_write_field(unicam, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
> > + /* trx_enable */
> > + unicam_reg_write_field(unicam, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
> > +
> > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_SOE);
> > +
> > + /* Packet compare setup - required to avoid missing frame ends */
> > + val = 0;
> > + unicam_set_field(&val, 1, UNICAM_PCE);
> > + unicam_set_field(&val, 1, UNICAM_GI);
> > + unicam_set_field(&val, 1, UNICAM_CPH);
> > + unicam_set_field(&val, 0, UNICAM_PCVC_MASK);
> > + unicam_set_field(&val, 1, UNICAM_PCDT_MASK);
> > + unicam_reg_write(unicam, UNICAM_CMP0, val);
> > +
> > + /* Enable clock lane and set up terminations */
> > + val = 0;
> > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > + /* CSI2 */
> > + unicam_set_field(&val, 1, UNICAM_CLE);
> > + unicam_set_field(&val, 1, UNICAM_CLLPE);
> > + if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > + unicam_set_field(&val, 1, UNICAM_CLTRE);
> > + unicam_set_field(&val, 1, UNICAM_CLHSE);
> > + }
> > + } else {
> > + /* CCP2 */
> > + unicam_set_field(&val, 1, UNICAM_CLE);
> > + unicam_set_field(&val, 1, UNICAM_CLHSE);
> > + unicam_set_field(&val, 1, UNICAM_CLTRE);
> > + }
> > + unicam_reg_write(unicam, UNICAM_CLK, val);
> > +
> > + /*
> > + * Enable required data lanes with appropriate terminations.
> > + * The same value needs to be written to UNICAM_DATn registers for
> > + * the active lanes, and 0 for inactive ones.
> > + */
> > + val = 0;
> > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > + /* CSI2 */
> > + unicam_set_field(&val, 1, UNICAM_DLE);
> > + unicam_set_field(&val, 1, UNICAM_DLLPE);
> > + if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > + unicam_set_field(&val, 1, UNICAM_DLTRE);
> > + unicam_set_field(&val, 1, UNICAM_DLHSE);
> > + }
> > + } else {
> > + /* CCP2 */
> > + unicam_set_field(&val, 1, UNICAM_DLE);
> > + unicam_set_field(&val, 1, UNICAM_DLHSE);
> > + unicam_set_field(&val, 1, UNICAM_DLTRE);
> > + }
> > + unicam_reg_write(unicam, UNICAM_DAT0, val);
> > +
> > + if (unicam->active_data_lanes == 1)
> > + val = 0;
> > + unicam_reg_write(unicam, UNICAM_DAT1, val);
> > +
> > + if (unicam->max_data_lanes > 2) {
> > + /*
> > + * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
> > + * instance supports more than 2 data lanes.
> > + */
> > + if (unicam->active_data_lanes == 2)
> > + val = 0;
> > + unicam_reg_write(unicam, UNICAM_DAT2, val);
> > +
> > + if (unicam->active_data_lanes == 3)
> > + val = 0;
> > + unicam_reg_write(unicam, UNICAM_DAT3, val);
> > + }
> > +
> > + unicam_reg_write(unicam, UNICAM_IBLS,
> > + node->fmt.fmt.pix.bytesperline);
> > + unicam_wr_dma_addr(&unicam->node[UNICAM_IMAGE_NODE], buf);
> > + unicam_set_packing_config(unicam);
> > + unicam_cfg_image_id(unicam);
> > +
> > + val = unicam_reg_read(unicam, UNICAM_MISC);
> > + unicam_set_field(&val, 1, UNICAM_FL0);
> > + unicam_set_field(&val, 1, UNICAM_FL1);
> > + unicam_reg_write(unicam, UNICAM_MISC, val);
> > +
> > + /* Enable peripheral */
> > + unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPE);
> > +
> > + /* Load image pointers */
> > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
> > +
> > + /*
> > + * Enable trigger only for the first frame to
> > + * sync correctly to the FS from the source.
> > + */
> > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > +}
[snip]
> > +static int unicam_async_nf_init(struct unicam_device *unicam)
> > +{
> > + struct v4l2_fwnode_endpoint ep = { };
>
> If the bus-type property is mandatory and you have no stated defaults
> anywhere, this is fine. I.e. all the relevant properties would need to be
> mandatory.
They are, as far as I can tell (well, the clock-noncontinuous property
is not mandatory, but that's expected as it's a flag).
> > + struct fwnode_handle *ep_handle;
> > + struct v4l2_async_connection *asc;
> > + int ret;
> > +
> > + ret = of_property_read_u32(unicam->dev->of_node, "brcm,num-data-lanes",
> > + &unicam->max_data_lanes);
> > + if (ret < 0) {
> > + dev_err(unicam->dev, "Missing %s DT property\n",
> > + "brcm,num-data-lanes");
> > + return -EINVAL;
> > + }
> > +
> > + /* Get and parse the local endpoint. */
> > + ep_handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(unicam->dev), 0, 0,
> > + FWNODE_GRAPH_ENDPOINT_NEXT);
> > + if (!ep_handle) {
> > + dev_err(unicam->dev, "No endpoint found\n");
> > + return -ENODEV;
> > + }
> > +
> > + ret = v4l2_fwnode_endpoint_parse(ep_handle, &ep);
> > + if (ret) {
> > + dev_err(unicam->dev, "Failed to parse endpoint: %d\n", ret);
> > + goto error;
> > + }
> > +
> > + unicam->bus_type = ep.bus_type;
> > +
> > + switch (ep.bus_type) {
> > + case V4L2_MBUS_CSI2_DPHY: {
> > + unsigned int num_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > +
> > + if (num_data_lanes != 1 && num_data_lanes != 2 &&
> > + num_data_lanes != 4) {
> > + dev_err(unicam->dev, "%u data lanes not supported\n",
> > + num_data_lanes);
> > + goto error;
> > + }
> > +
> > + if (num_data_lanes > unicam->max_data_lanes) {
> > + dev_err(unicam->dev,
> > + "Endpoint uses %u data lanes when %u are supported\n",
> > + num_data_lanes, unicam->max_data_lanes);
> > + goto error;
> > + }
> > +
> > + unicam->active_data_lanes = num_data_lanes;
> > + unicam->bus_flags = ep.bus.mipi_csi2.flags;
> > + break;
> > + }
> > +
> > + case V4L2_MBUS_CCP2:
> > + unicam->max_data_lanes = 1;
> > + unicam->active_data_lanes = 1;
> > + unicam->bus_flags = ep.bus.mipi_csi1.strobe;
> > + break;
> > +
> > + default:
> > + /* Unsupported bus type */
> > + dev_err(unicam->dev, "Unsupported bus type %u\n", ep.bus_type);
> > + goto error;
> > + }
> > +
> > + /* Initialize and register the async notifier. */
> > + v4l2_async_nf_init(&unicam->notifier, &unicam->v4l2_dev);
> > +
> > + asc = v4l2_async_nf_add_fwnode_remote(&unicam->notifier, ep_handle,
> > + struct v4l2_async_connection);
> > + fwnode_handle_put(ep_handle);
> > + ep_handle = NULL;
> > +
> > + if (IS_ERR(asc)) {
> > + ret = PTR_ERR(asc);
> > + dev_err(unicam->dev, "Failed to add entry to notifier: %d\n",
> > + ret);
> > + goto error;
> > + }
> > +
> > + unicam->notifier.ops = &unicam_async_ops;
> > +
> > + ret = v4l2_async_nf_register(&unicam->notifier);
> > + if (ret) {
> > + dev_err(unicam->dev, "Error registering device notifier: %d\n",
> > + ret);
> > + goto error;
> > + }
> > +
> > + return 0;
> > +
> > +error:
> > + fwnode_handle_put(ep_handle);
> > + return ret;
> > +}
> > +
> > +/* -----------------------------------------------------------------------------
> > + * Probe & remove
> > + */
> > +
> > +static int unicam_media_init(struct unicam_device *unicam)
> > +{
> > + int ret;
> > +
> > + unicam->mdev.dev = unicam->dev;
> > + strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
> > + sizeof(unicam->mdev.model));
> > + strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
>
> Isn't the field already zeroed?
Indeed. I'll drop this.
>
> > + unicam->mdev.hw_revision = 0;
> > +
> > + media_device_init(&unicam->mdev);
> > +
> > + unicam->v4l2_dev.mdev = &unicam->mdev;
> > +
> > + ret = v4l2_device_register(unicam->dev, &unicam->v4l2_dev);
> > + if (ret < 0) {
> > + dev_err(unicam->dev, "Unable to register v4l2 device\n");
> > + goto err_media_cleanup;
> > + }
> > +
> > + ret = media_device_register(&unicam->mdev);
> > + if (ret < 0) {
> > + dev_err(unicam->dev,
> > + "Unable to register media-controller device\n");
> > + goto err_v4l2_unregister;
> > + }
> > +
> > + return 0;
> > +
> > +err_v4l2_unregister:
> > + v4l2_device_unregister(&unicam->v4l2_dev);
> > +err_media_cleanup:
> > + media_device_cleanup(&unicam->mdev);
> > + return ret;
> > +}
[snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH] of: property: fw_devlink: Fix stupid bug in remote-endpoint parsing
From: John Watts @ 2024-03-26 1:42 UTC (permalink / raw)
To: Saravana Kannan
Cc: Rob Herring, Frank Rowand, Hervé Codina, Luca Ceresoli,
kernel-team, Rob Herring, devicetree, linux-kernel
In-Reply-To: <CAGETcx-Emvu41nB3UDnb4Gh2aJEKu_hFcHX89uWnBTnaqvpN8g@mail.gmail.com>
On Mon, Mar 25, 2024 at 06:35:45PM -0700, Saravana Kannan wrote:
> Ok, I have a solution. Have the audio-graph-card2 find the fwnode of
> "multi" and mark it as "not a device" by doing something like this in
> the driver. That should help fw_devlink handle this correctly.
>
> fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
I'll test this out, thanks.
> Definitely do this though as a forward looking improvement. It'll help
> make the suspend/resume more deterministic and will eventually let
> things happen in an async manner.
Is there a way to also do this in the driver?
> -Saravana
John.
^ permalink raw reply
* [PATCH v5 0/3] riscv: sophgo: add dmamux support for Sophgo CV1800/SG2000 SoCs
From: Inochi Amaoto @ 2024-03-26 1:44 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
Add dma multiplexer support for the Sophgo CV1800/SG2000 SoCs.
Changed from v4:
1. remove the syscon binding since it can not be complete (still
lack some subdevices)
2. add reg description for the binding,
3. remove the fixed channel assign for dmamux binding
3. driver adopt to the binding change. Now the driver allocates all the
channel when initing and maps the request chan to the channel dynamicly.
Changed from v3:
1. fix dt-binding address issue.
Changed from v2:
1. add reg property of dmamux node in the binding of patch 2
Changed from v1:
1. fix wrong title of patch 2.
Inochi Amaoto (3):
dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
dmaengine: add driver for Sophgo CV18XX/SG200X dmamux
.../bindings/dma/sophgo,cv1800-dmamux.yaml | 48 ++++
drivers/dma/Kconfig | 9 +
drivers/dma/Makefile | 1 +
drivers/dma/cv1800-dmamux.c | 268 ++++++++++++++++++
include/dt-bindings/dma/cv1800-dma.h | 55 ++++
include/soc/sophgo/cv1800-sysctl.h | 30 ++
6 files changed, 411 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
create mode 100644 drivers/dma/cv1800-dmamux.c
create mode 100644 include/dt-bindings/dma/cv1800-dma.h
create mode 100644 include/soc/sophgo/cv1800-sysctl.h
--
2.44.0
^ permalink raw reply
* [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26 1:47 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
an additional channel remap register located in the top system control
area. The DMA channel is exclusive to each core.
Add the dmamux binding for CV18XX/SG200X series SoC
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
.../bindings/dma/sophgo,cv1800-dmamux.yaml | 48 ++++++++++++++++
include/dt-bindings/dma/cv1800-dma.h | 55 +++++++++++++++++++
2 files changed, 103 insertions(+)
create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
create mode 100644 include/dt-bindings/dma/cv1800-dma.h
diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
new file mode 100644
index 000000000000..d7256646ea26
--- /dev/null
+++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sophgo CV1800/SG200 Series DMA mux
+
+maintainers:
+ - Inochi Amaoto <inochiama@outlook.com>
+
+allOf:
+ - $ref: dma-router.yaml#
+
+properties:
+ compatible:
+ const: sophgo,cv1800-dmamux
+
+ reg:
+ items:
+ - description: DMA channal remapping register
+ - description: DMA channel interrupt mapping register
+
+ '#dma-cells':
+ const: 2
+ description:
+ The first cells is device id. The second one is the cpu id.
+
+ dma-masters:
+ maxItems: 1
+
+ dma-requests:
+ const: 8
+
+required:
+ - '#dma-cells'
+ - dma-masters
+
+additionalProperties: false
+
+examples:
+ - |
+ dma-router {
+ compatible = "sophgo,cv1800-dmamux";
+ #dma-cells = <2>;
+ dma-masters = <&dmac>;
+ dma-requests = <8>;
+ };
diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
new file mode 100644
index 000000000000..3ce9dac25259
--- /dev/null
+++ b/include/dt-bindings/dma/cv1800-dma.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
+
+#ifndef __DT_BINDINGS_DMA_CV1800_H__
+#define __DT_BINDINGS_DMA_CV1800_H__
+
+#define DMA_I2S0_RX 0
+#define DMA_I2S0_TX 1
+#define DMA_I2S1_RX 2
+#define DMA_I2S1_TX 3
+#define DMA_I2S2_RX 4
+#define DMA_I2S2_TX 5
+#define DMA_I2S3_RX 6
+#define DMA_I2S3_TX 7
+#define DMA_UART0_RX 8
+#define DMA_UART0_TX 9
+#define DMA_UART1_RX 10
+#define DMA_UART1_TX 11
+#define DMA_UART2_RX 12
+#define DMA_UART2_TX 13
+#define DMA_UART3_RX 14
+#define DMA_UART3_TX 15
+#define DMA_SPI0_RX 16
+#define DMA_SPI0_TX 17
+#define DMA_SPI1_RX 18
+#define DMA_SPI1_TX 19
+#define DMA_SPI2_RX 20
+#define DMA_SPI2_TX 21
+#define DMA_SPI3_RX 22
+#define DMA_SPI3_TX 23
+#define DMA_I2C0_RX 24
+#define DMA_I2C0_TX 25
+#define DMA_I2C1_RX 26
+#define DMA_I2C1_TX 27
+#define DMA_I2C2_RX 28
+#define DMA_I2C2_TX 29
+#define DMA_I2C3_RX 30
+#define DMA_I2C3_TX 31
+#define DMA_I2C4_RX 32
+#define DMA_I2C4_TX 33
+#define DMA_TDM0_RX 34
+#define DMA_TDM0_TX 35
+#define DMA_TDM1_RX 36
+#define DMA_AUDSRC 37
+#define DMA_SPI_NAND 38
+#define DMA_SPI_NOR 39
+#define DMA_UART4_RX 40
+#define DMA_UART4_TX 41
+#define DMA_SPI_NOR1 42
+
+#define DMA_CPU_A53 0
+#define DMA_CPU_C906_0 1
+#define DMA_CPU_C906_1 2
+
+
+#endif // __DT_BINDINGS_DMA_CV1800_H__
--
2.44.0
^ permalink raw reply related
* [PATCH v5 2/3] soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
From: Inochi Amaoto @ 2024-03-26 1:47 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
The "top" system controller of CV18XX/SG200X exposes control
register access for various devices. Add soc header file to
describe it.
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
include/soc/sophgo/cv1800-sysctl.h | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 include/soc/sophgo/cv1800-sysctl.h
diff --git a/include/soc/sophgo/cv1800-sysctl.h b/include/soc/sophgo/cv1800-sysctl.h
new file mode 100644
index 000000000000..b9396d33e240
--- /dev/null
+++ b/include/soc/sophgo/cv1800-sysctl.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#ifndef CV1800_SYSCTL_H
+#define CV1800_SYSCTL_H
+
+/*
+ * SOPHGO CV1800/SG2000 SoC top system controller registers offsets.
+ */
+
+#define CV1800_CONF_INFO 0x004
+#define CV1800_SYS_CTRL_REG 0x008
+#define CV1800_USB_PHY_CTRL_REG 0x048
+#define CV1800_SDMA_DMA_CHANNEL_REMAP0 0x154
+#define CV1800_SDMA_DMA_CHANNEL_REMAP1 0x158
+#define CV1800_TOP_TIMER_CLK_SEL 0x1a0
+#define CV1800_TOP_WDT_CTRL 0x1a8
+#define CV1800_DDR_AXI_URGENT_OW 0x1b8
+#define CV1800_DDR_AXI_URGENT 0x1bc
+#define CV1800_DDR_AXI_QOS_0 0x1d8
+#define CV1800_DDR_AXI_QOS_1 0x1dc
+#define CV1800_SD_PWRSW_CTRL 0x1f4
+#define CV1800_SD_PWRSW_TIME 0x1f8
+#define CV1800_DDR_AXI_QOS_OW 0x23c
+#define CV1800_SD_CTRL_OPT 0x294
+#define CV1800_SDMA_DMA_INT_MUX 0x298
+
+#endif // CV1800_SYSCTL_H
--
2.44.0
^ permalink raw reply related
* [PATCH v5 3/3] dmaengine: add driver for Sophgo CV18XX/SG200X dmamux
From: Inochi Amaoto @ 2024-03-26 1:47 UTC (permalink / raw)
To: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Inochi Amaoto, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953B500D7451964EE37DA4CBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
Sophgo CV18XX/SG200X use DW AXI CORE with a multiplexer for remapping
its request lines. The multiplexer supports at most 8 request lines.
Add driver for Sophgo CV18XX/SG200X DMA multiplexer.
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
drivers/dma/Kconfig | 9 ++
drivers/dma/Makefile | 1 +
drivers/dma/cv1800-dmamux.c | 268 ++++++++++++++++++++++++++++++++++++
3 files changed, 278 insertions(+)
create mode 100644 drivers/dma/cv1800-dmamux.c
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 002a5ec80620..cb31520b9f86 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -546,6 +546,15 @@ config PLX_DMA
These are exposed via extra functions on the switch's
upstream port. Each function exposes one DMA channel.
+config SOPHGO_CV1800_DMAMUX
+ tristate "Sophgo CV1800/SG2000 series SoC DMA multiplexer support"
+ depends on MFD_SYSCON
+ depends on ARCH_SOPHGO
+ help
+ Support for the DMA multiplexer on Sophgo CV1800/SG2000
+ series SoCs.
+ Say Y here if your board have this soc.
+
config STE_DMA40
bool "ST-Ericsson DMA40 support"
depends on ARCH_U8500
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index dfd40d14e408..7465f249ee47 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
obj-$(CONFIG_PXA_DMA) += pxa_dma.o
obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_SF_PDMA) += sf-pdma/
+obj-$(CONFIG_SOPHGO_CV1800_DMAMUX) += cv1800-dmamux.o
obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_STM32_DMA) += stm32-dma.o
obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o
diff --git a/drivers/dma/cv1800-dmamux.c b/drivers/dma/cv1800-dmamux.c
new file mode 100644
index 000000000000..9c01f157ab97
--- /dev/null
+++ b/drivers/dma/cv1800-dmamux.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/of_dma.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/llist.h>
+#include <linux/regmap.h>
+#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
+
+#include <soc/sophgo/cv1800-sysctl.h>
+#include <dt-bindings/dma/cv1800-dma.h>
+
+#define DMAMUX_NCELLS 2
+#define MAX_DMA_MAPPING_ID DMA_SPI_NOR1
+#define MAX_DMA_CPU_ID DMA_CPU_C906_1
+#define MAX_DMA_CH_ID 7
+
+#define DMAMUX_INTMUX_REGISTER_LEN 4
+#define DMAMUX_NR_CH_PER_REGISTER 4
+#define DMAMUX_BIT_PER_CH 8
+#define DMAMUX_CH_MASk GENMASK(5, 0)
+#define DMAMUX_INT_BIT_PER_CPU 10
+#define DMAMUX_CH_UPDATE_BIT BIT(31)
+
+#define DMAMUX_CH_REGPOS(chid) \
+ ((chid) / DMAMUX_NR_CH_PER_REGISTER)
+#define DMAMUX_CH_REGOFF(chid) \
+ ((chid) % DMAMUX_NR_CH_PER_REGISTER)
+#define DMAMUX_CH_REG(chid) \
+ ((DMAMUX_CH_REGPOS(chid) * sizeof(u32)) + \
+ CV1800_SDMA_DMA_CHANNEL_REMAP0)
+#define DMAMUX_CH_SET(chid, val) \
+ (((val) << (DMAMUX_CH_REGOFF(chid) * DMAMUX_BIT_PER_CH)) | \
+ DMAMUX_CH_UPDATE_BIT)
+#define DMAMUX_CH_MASK(chid) \
+ DMAMUX_CH_SET(chid, DMAMUX_CH_MASk)
+
+#define DMAMUX_INT_BIT(chid, cpuid) \
+ BIT((cpuid) * DMAMUX_INT_BIT_PER_CPU + (chid))
+#define DMAMUX_INTEN_BIT(cpuid) \
+ DMAMUX_INT_BIT(8, cpuid)
+#define DMAMUX_INT_CH_BIT(chid, cpuid) \
+ (DMAMUX_INT_BIT(chid, cpuid) | DMAMUX_INTEN_BIT(cpuid))
+#define DMAMUX_INT_MASK(chid) \
+ (DMAMUX_INT_BIT(chid, DMA_CPU_A53) | \
+ DMAMUX_INT_BIT(chid, DMA_CPU_C906_0) | \
+ DMAMUX_INT_BIT(chid, DMA_CPU_C906_1))
+#define DMAMUX_INT_CH_MASK(chid, cpuid) \
+ (DMAMUX_INT_MASK(chid) | DMAMUX_INTEN_BIT(cpuid))
+
+struct cv1800_dmamux_data {
+ struct dma_router dmarouter;
+ struct regmap *regmap;
+ spinlock_t lock;
+ struct llist_head free_maps;
+ struct llist_head reserve_maps;
+ DECLARE_BITMAP(mapped_peripherals, MAX_DMA_MAPPING_ID);
+};
+
+struct cv1800_dmamux_map {
+ struct llist_node node;
+ unsigned int channel;
+ unsigned int peripheral;
+ unsigned int cpu;
+};
+
+static void cv1800_dmamux_free(struct device *dev, void *route_data)
+{
+ struct cv1800_dmamux_data *dmamux = dev_get_drvdata(dev);
+ struct cv1800_dmamux_map *map = route_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dmamux->lock, flags);
+
+ regmap_update_bits(dmamux->regmap,
+ DMAMUX_CH_REG(map->channel),
+ DMAMUX_CH_MASK(map->channel),
+ DMAMUX_CH_UPDATE_BIT);
+
+ regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
+ DMAMUX_INT_CH_MASK(map->channel, map->cpu),
+ DMAMUX_INTEN_BIT(map->cpu));
+
+ spin_unlock_irqrestore(&dmamux->lock, flags);
+
+ dev_info(dev, "free channel %u for req %u (cpu %u)\n",
+ map->channel, map->peripheral, map->cpu);
+}
+
+static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
+ struct cv1800_dmamux_data *dmamux = platform_get_drvdata(pdev);
+ struct cv1800_dmamux_map *map;
+ struct llist_node *node;
+ unsigned long flags;
+ unsigned int chid, devid, cpuid;
+ int ret;
+
+ if (dma_spec->args_count != DMAMUX_NCELLS) {
+ dev_err(&pdev->dev, "invalid number of dma mux args\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ devid = dma_spec->args[0];
+ cpuid = dma_spec->args[1];
+ dma_spec->args_count = 1;
+
+ if (devid > MAX_DMA_MAPPING_ID) {
+ dev_err(&pdev->dev, "invalid device id: %u\n", devid);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (cpuid > MAX_DMA_CPU_ID) {
+ dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid);
+ return ERR_PTR(-EINVAL);
+ }
+
+ dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
+ if (!dma_spec->np) {
+ dev_err(&pdev->dev, "can't get dma master\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ spin_lock_irqsave(&dmamux->lock, flags);
+
+ if (test_bit(devid, dmamux->mapped_peripherals)) {
+ llist_for_each_entry(map, dmamux->reserve_maps.first, node) {
+ if (map->peripheral == devid && map->cpu == cpuid)
+ goto found;
+ }
+
+ ret = -EINVAL;
+ goto failed;
+ } else {
+ node = llist_del_first(&dmamux->free_maps);
+ if (!node) {
+ ret = -ENODEV;
+ goto failed;
+ }
+
+ map = llist_entry(node, struct cv1800_dmamux_map, node);
+ llist_add(&map->node, &dmamux->reserve_maps);
+ set_bit(devid, dmamux->mapped_peripherals);
+ }
+
+found:
+ chid = map->channel;
+ map->peripheral = devid;
+ map->cpu = cpuid;
+
+ regmap_set_bits(dmamux->regmap,
+ DMAMUX_CH_REG(chid),
+ DMAMUX_CH_SET(chid, devid));
+
+ regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
+ DMAMUX_INT_CH_MASK(chid, cpuid),
+ DMAMUX_INT_CH_BIT(chid, cpuid));
+
+ spin_unlock_irqrestore(&dmamux->lock, flags);
+
+ dma_spec->args[0] = chid;
+
+ dev_info(&pdev->dev, "register channel %u for req %u (cpu %u)\n",
+ chid, devid, cpuid);
+
+ return map;
+
+failed:
+ spin_unlock_irqrestore(&dmamux->lock, flags);
+ of_node_put(dma_spec->np);
+ dev_err(&pdev->dev, "errno %d\n", ret);
+ return ERR_PTR(ret);
+
+}
+
+static int cv1800_dmamux_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *mux_node = dev->of_node;
+ struct cv1800_dmamux_data *data;
+ struct cv1800_dmamux_map *tmp;
+ struct device *parent = dev->parent;
+ struct device_node *dma_master;
+ struct regmap *regmap = NULL;
+ unsigned int i;
+
+ if (!parent)
+ return -ENODEV;
+
+ regmap = device_node_to_regmap(parent->of_node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ dma_master = of_parse_phandle(mux_node, "dma-masters", 0);
+ if (!dma_master) {
+ dev_err(dev, "invalid dma-requests property\n");
+ return -ENODEV;
+ }
+ of_node_put(dma_master);
+
+ data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+ init_llist_head(&data->free_maps);
+
+ for (i = 0; i <= MAX_DMA_CH_ID; i++) {
+ tmp = devm_kmalloc(dev, sizeof(*tmp), GFP_KERNEL);
+ if (!tmp) {
+ /* It is OK for not allocating all channel */
+ dev_warn(dev, "can not allocate channel %u\n", i);
+ continue;
+ }
+
+ init_llist_node(&tmp->node);
+ tmp->channel = i;
+ llist_add(&tmp->node, &data->free_maps);
+ }
+
+ /* if no channel is allocated, the probe must fail */
+ if (llist_empty(&data->free_maps))
+ return -ENOMEM;
+
+ data->regmap = regmap;
+ data->dmarouter.dev = dev;
+ data->dmarouter.route_free = cv1800_dmamux_free;
+
+ platform_set_drvdata(pdev, data);
+
+ return of_dma_router_register(mux_node,
+ cv1800_dmamux_route_allocate,
+ &data->dmarouter);
+}
+
+static void cv1800_dmamux_remove(struct platform_device *pdev)
+{
+ of_dma_controller_free(pdev->dev.of_node);
+}
+
+static const struct of_device_id cv1800_dmamux_ids[] = {
+ { .compatible = "sophgo,cv1800-dmamux", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cv1800_dmamux_ids);
+
+static struct platform_driver cv1800_dmamux_driver = {
+ .driver = {
+ .name = "cv1800-dmamux",
+ .of_match_table = cv1800_dmamux_ids,
+ },
+ .probe = cv1800_dmamux_probe,
+ .remove_new = cv1800_dmamux_remove,
+};
+module_platform_driver(cv1800_dmamux_driver);
+
+MODULE_AUTHOR("Inochi Amaoto <inochiama@outlook.com>");
+MODULE_DESCRIPTION("Sophgo CV1800/SG2000 Series Soc DMAMUX driver");
+MODULE_LICENSE("GPL");
--
2.44.0
^ permalink raw reply related
* Re: [PATCH v6 09/15] media: bcm2835-unicam: Add support for CCP2/CSI2 camera interface
From: Laurent Pinchart @ 2024-03-26 1:50 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media, Dave Stevenson, David Plowman, Jean-Michel Hautbois,
Hans Verkuil, Naushir Patuck, kernel-list, linux-rpi-kernel,
Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list, Conor Dooley, Krzysztof Kozlowski,
Rob Herring, devicetree
In-Reply-To: <20240326013708.GA31396@pendragon.ideasonboard.com>
On Tue, Mar 26, 2024 at 03:37:09AM +0200, Laurent Pinchart wrote:
> Hi Sakari,
>
> On Mon, Mar 25, 2024 at 06:36:49PM +0000, Sakari Ailus wrote:
> > On Fri, Mar 01, 2024 at 11:32:24PM +0200, Laurent Pinchart wrote:
> > > From: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > >
> > > Add a driver for the Unicam camera receiver block on BCM283x processors.
> > > It is represented as two video device nodes: unicam-image and
> > > unicam-embedded which are connected to an internal subdev (named
> > > unicam-subdev) in order to manage streams routing.
> > >
> > > Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > Co-developed-by: Naushir Patuck <naush@raspberrypi.com>
> > > Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> > > Co-developed-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > > Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>
> > > Co-developed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> > > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> >
> > Thanks for submitting this, it's the cleanest and neatest Unicom driver
>
> Unicam, or if you insist Unicorn, but not Unicom :-)
>
> > I've ever seen!
> >
> > Some mostly unimportant comments below, however the bus-type issue needs to
> > be addressed.
> >
> > > ---
> > > Changes since v5:
> > >
> > > - Move to drivers/media/platform/broadcom/
> > > - Port to the upstream V4L2 streams API
> > > - Rebase on latest metadata API proposal
> > > - Add missing error message
> > > - Drop unneeded documentation block for unicam_isr()
> > > - Drop unneeded dev_dbg() and dev_err() messages
> > > - Drop unneeded streams_mask and fmt checks
> > > - Drop unused unicam_sd_pad_is_sink()
> > > - Drop unneeded includes
> > > - Drop v4l2_ctrl_subscribe_event() call
> > > - Use pm_runtime_resume_and_get()
> > > - Indentation and line wrap fixes
> > > - Let the framework set bus_info
> > > - Use v4l2_fwnode_endpoint_parse()
> > > - Fix media device cleanup
> > > - Drop lane reordering checks
> > > - Fix subdev state locking
> > > - Drop extra debug messages
> > > - Move clock handling to runtime PM handlers
> > > - Reorder functions
> > > - Rename init functions for more clarity
> > > - Initialize runtime PM earlier
> > > - Clarify error messages
> > > - Simplify subdev init with local variable
> > > - Fix subdev cleanup
> > > - Fix typos and indentation
> > > - Don't initialize local variables needlessly
> > > - Simplify num lanes check
> > > - Fix metadata handling in subdev set_fmt
> > > - Drop manual fallback to .s_stream()
> > > - Pass v4l2_pix_format to unicam_calc_format_size_bpl()
> > > - Simplify unicam_set_default_format()
> > > - Fix default format settings
> > > - Add busy check in unicam_s_fmt_meta()
> > > - Add missing \n at end of format strings
> > > - Fix metadata handling in subdev set_fmt
> > > - Fix locking when starting streaming
> > > - Return buffers from start streaming fails
> > > - Fix format validation for metadata node
> > > - Use video_device_pipeline_{start,stop}() helpers
> > > - Simplify format enumeration
> > > - Drop unset variable
> > > - Update MAINTAINERS entry
> > > - Update to the upstream v4l2_async_nf API
> > > - Update to the latest subdev routing API
> > > - Update to the latest subdev state API
> > > - Move from subdev .init_cfg() to .init_state()
> > > - Update to the latest videobuf2 API
> > > - Fix v4l2_subdev_enable_streams() error check
> > > - Use correct pad for the connected subdev
> > > - Return buffers to vb2 when start streaming fails
> > > - Improve debugging in start streaming handler
> > > - Simplify DMA address management
> > > - Drop comment about bcm2835-camera driver
> > > - Clarify comments that explain min/max sizes
> > > - Pass v4l2_pix_format to unicam_try_fmt()
> > > - Drop unneeded local variables
> > > - Rename image-related constants and functions
> > > - Turn unicam_fmt.metadata_fmt into bool
> > > - Rename unicam_fmt to unicam_format_info
> > > - Rename unicam_format_info variables to fmtinfo
> > > - Rename unicam_node.v_fmt to fmt
> > > - Add metadata formats for RAW10, RAW12 and RAW14
> > > - Make metadata formats line-based
> > > - Validate format on metadata video device
> > > - Add Co-devlopped-by tags
> > >
> > > Changes since v3:
> > >
> > > - Add the vendor prefix for DT name
> > > - Use the reg-names in DT parsing
> > > - Remove MAINTAINERS entry
> > >
> > > Changes since v2:
> > >
> > > - Change code organization
> > > - Remove unused variables
> > > - Correct the fmt_meta functions
> > > - Rewrite the start/stop streaming
> > > - You can now start the image node alone, but not the metadata one
> > > - The buffers are allocated per-node
> > > - only the required stream is started, if the route exists and is
> > > enabled
> > > - Prefix the macros with UNICAM_ to not have too generic names
> > > - Drop colorspace support
> > >
> > > Changes since v1:
> > >
> > > - Replace the unicam_{info,debug,error} macros with dev_*()
> > > ---
> > > MAINTAINERS | 1 +
> > > drivers/media/platform/Kconfig | 1 +
> > > drivers/media/platform/Makefile | 1 +
> > > drivers/media/platform/broadcom/Kconfig | 23 +
> > > drivers/media/platform/broadcom/Makefile | 3 +
> > > .../platform/broadcom/bcm2835-unicam-regs.h | 255 ++
> > > .../media/platform/broadcom/bcm2835-unicam.c | 2607 +++++++++++++++++
> > > 7 files changed, 2891 insertions(+)
> > > create mode 100644 drivers/media/platform/broadcom/Kconfig
> > > create mode 100644 drivers/media/platform/broadcom/Makefile
> > > create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > > create mode 100644 drivers/media/platform/broadcom/bcm2835-unicam.c
> > >
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index e50a59654e6e..cc350729f467 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -4002,6 +4002,7 @@ M: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
> > > L: linux-media@vger.kernel.org
> > > S: Maintained
> > > F: Documentation/devicetree/bindings/media/brcm,bcm2835-unicam.yaml
> > > +F: drivers/media/platform/bcm2835/
> > >
> > > BROADCOM BCM47XX MIPS ARCHITECTURE
> > > M: Hauke Mehrtens <hauke@hauke-m.de>
> > > diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
> > > index 91e54215de3a..2d79bfc68c15 100644
> > > --- a/drivers/media/platform/Kconfig
> > > +++ b/drivers/media/platform/Kconfig
> > > @@ -67,6 +67,7 @@ source "drivers/media/platform/amlogic/Kconfig"
> > > source "drivers/media/platform/amphion/Kconfig"
> > > source "drivers/media/platform/aspeed/Kconfig"
> > > source "drivers/media/platform/atmel/Kconfig"
> > > +source "drivers/media/platform/broadcom/Kconfig"
> > > source "drivers/media/platform/cadence/Kconfig"
> > > source "drivers/media/platform/chips-media/Kconfig"
> > > source "drivers/media/platform/intel/Kconfig"
> > > diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> > > index 3296ec1ebe16..da17301f7439 100644
> > > --- a/drivers/media/platform/Makefile
> > > +++ b/drivers/media/platform/Makefile
> > > @@ -10,6 +10,7 @@ obj-y += amlogic/
> > > obj-y += amphion/
> > > obj-y += aspeed/
> > > obj-y += atmel/
> > > +obj-y += broadcom/
> > > obj-y += cadence/
> > > obj-y += chips-media/
> > > obj-y += intel/
> > > diff --git a/drivers/media/platform/broadcom/Kconfig b/drivers/media/platform/broadcom/Kconfig
> > > new file mode 100644
> > > index 000000000000..cc2c9afcc948
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/Kconfig
> > > @@ -0,0 +1,23 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +config VIDEO_BCM2835_UNICAM
> > > + tristate "Broadcom BCM283x/BCM271x Unicam video capture driver"
> > > + depends on ARCH_BCM2835 || COMPILE_TEST
> > > + depends on PM
> > > + depends on VIDEO_DEV
> > > + select MEDIA_CONTROLLER
> > > + select V4L2_FWNODE
> > > + select VIDEO_V4L2_SUBDEV_API
> > > + select VIDEOBUF2_DMA_CONTIG
> > > + help
> > > + Say Y here to enable support for the BCM283x/BCM271x CSI-2 receiver.
> > > + This is a V4L2 driver that controls the CSI-2 receiver directly,
> > > + independently from the VC4 firmware.
> > > +
> > > + This driver is mutually exclusive with the use of bcm2835-camera. The
> > > + firmware will disable all access to the peripheral from within the
> > > + firmware if it finds a DT node using it, and bcm2835-camera will
> > > + therefore fail to probe.
> > > +
> > > + To compile this driver as a module, choose M here. The module will be
> > > + called bcm2835-unicam.
> > > diff --git a/drivers/media/platform/broadcom/Makefile b/drivers/media/platform/broadcom/Makefile
> > > new file mode 100644
> > > index 000000000000..03d2045aba2e
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/Makefile
> > > @@ -0,0 +1,3 @@
> > > +# SPDX-License-Identifier: GPL-2.0
> > > +
> > > +obj-$(CONFIG_VIDEO_BCM2835_UNICAM) += bcm2835-unicam.o
> > > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam-regs.h b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > > new file mode 100644
> > > index 000000000000..84775fd2fac5
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/bcm2835-unicam-regs.h
> > > @@ -0,0 +1,255 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +
> > > +/*
> > > + * Copyright (C) 2017-2020 Raspberry Pi Trading.
> >
> > Anything up to 2024?
>
> Not really. The registers haven't really changed :-) I'll update the
> copyright in the .c file though.
>
> > > + * Dave Stevenson <dave.stevenson@raspberrypi.com>
> > > + */
>
> [snip]
>
> > > diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > new file mode 100644
> > > index 000000000000..716c89b8a217
> > > --- /dev/null
> > > +++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
> > > @@ -0,0 +1,2607 @@
>
> [snip]
>
> > > +static irqreturn_t unicam_isr(int irq, void *dev)
> > > +{
> > > + struct unicam_device *unicam = dev;
> > > + unsigned int lines_done = unicam_get_lines_done(dev);
> > > + unsigned int sequence = unicam->sequence;
> > > + unsigned int i;
> > > + u32 ista, sta;
> > > + bool fe;
> > > + u64 ts;
> > > +
> > > + sta = unicam_reg_read(unicam, UNICAM_STA);
> > > + /* Write value back to clear the interrupts */
> > > + unicam_reg_write(unicam, UNICAM_STA, sta);
> > > +
> > > + ista = unicam_reg_read(unicam, UNICAM_ISTA);
> > > + /* Write value back to clear the interrupts */
> > > + unicam_reg_write(unicam, UNICAM_ISTA, ista);
> > > +
> > > + dev_dbg(unicam->dev, "ISR: ISTA: 0x%X, STA: 0x%X, sequence %d, lines done %d\n",
> > > + ista, sta, sequence, lines_done);
> > > +
> > > + if (!(sta & (UNICAM_IS | UNICAM_PI0)))
> > > + return IRQ_HANDLED;
> > > +
> > > + /*
> > > + * Look for either the Frame End interrupt or the Packet Capture status
> > > + * to signal a frame end.
> > > + */
> > > + fe = ista & UNICAM_FEI || sta & UNICAM_PI0;
> > > +
> > > + /*
> > > + * We must run the frame end handler first. If we have a valid next_frm
> > > + * and we get a simultaneout FE + FS interrupt, running the FS handler
> > > + * first would null out the next_frm ptr and we would have lost the
> > > + * buffer forever.
> > > + */
> > > + if (fe) {
> > > + /*
> > > + * Ensure we have swapped buffers already as we can't
> > > + * stop the peripheral. If no buffer is available, use a
> > > + * dummy buffer to dump out frames until we get a new buffer
> > > + * to use.
> > > + */
> > > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > > + if (!unicam->node[i].streaming)
> > > + continue;
> > > +
> > > + /*
> > > + * If cur_frm == next_frm, it means we have not had
> > > + * a chance to swap buffers, likely due to having
> > > + * multiple interrupts occurring simultaneously (like FE
> > > + * + FS + LS). In this case, we cannot signal the buffer
> > > + * as complete, as the HW will reuse that buffer.
> > > + */
> > > + if (unicam->node[i].cur_frm &&
> > > + unicam->node[i].cur_frm != unicam->node[i].next_frm)
> > > + unicam_process_buffer_complete(&unicam->node[i],
> > > + sequence);
> > > + unicam->node[i].cur_frm = unicam->node[i].next_frm;
> > > + }
> > > + unicam->sequence++;
> >
> > Does access to this data need to be serialised somehow.
>
> Given that it's only accessed from the interrupt handler (beside
> start_streaming time, before starting the hardware), I don't think so.
>
> > > + }
> > > +
> > > + if (ista & UNICAM_FSI) {
> > > + /*
> > > + * Timestamp is to be when the first data byte was captured,
> > > + * aka frame start.
> > > + */
> > > + ts = ktime_get_ns();
> > > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > > + if (!unicam->node[i].streaming)
> > > + continue;
> > > +
> > > + if (unicam->node[i].cur_frm)
> > > + unicam->node[i].cur_frm->vb.vb2_buf.timestamp =
> > > + ts;
> > > + else
> > > + dev_dbg(unicam->v4l2_dev.dev,
> > > + "ISR: [%d] Dropping frame, buffer not available at FS\n",
> > > + i);
> > > + /*
> > > + * Set the next frame output to go to a dummy frame
> > > + * if we have not managed to obtain another frame
> > > + * from the queue.
> > > + */
> > > + unicam_schedule_dummy_buffer(&unicam->node[i]);
> > > + }
> > > +
> > > + unicam_queue_event_sof(unicam);
> > > + }
> > > +
> > > + /*
> > > + * Cannot swap buffer at frame end, there may be a race condition
> > > + * where the HW does not actually swap it if the new frame has
> > > + * already started.
> > > + */
> > > + if (ista & (UNICAM_FSI | UNICAM_LCI) && !fe) {
> > > + for (i = 0; i < ARRAY_SIZE(unicam->node); i++) {
> > > + if (!unicam->node[i].streaming)
> > > + continue;
> > > +
> > > + spin_lock(&unicam->node[i].dma_queue_lock);
> > > + if (!list_empty(&unicam->node[i].dma_queue) &&
> > > + !unicam->node[i].next_frm)
> > > + unicam_schedule_next_buffer(&unicam->node[i]);
> > > + spin_unlock(&unicam->node[i].dma_queue_lock);
> > > + }
> > > + }
> > > +
> > > + if (unicam_reg_read(unicam, UNICAM_ICTL) & UNICAM_FCM) {
> > > + /* Switch out of trigger mode if selected */
> > > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > > + unicam_reg_write_field(unicam, UNICAM_ICTL, 0, UNICAM_FCM);
> > > + }
> > > + return IRQ_HANDLED;
> > > +}
> > > +
> > > +static void unicam_set_packing_config(struct unicam_device *unicam)
> > > +{
> > > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > + u32 pack, unpack;
> > > + u32 val;
> > > +
> > > + if (node->fmt.fmt.pix.pixelformat == node->fmtinfo->fourcc) {
> > > + unpack = UNICAM_PUM_NONE;
> > > + pack = UNICAM_PPM_NONE;
> > > + } else {
> > > + switch (node->fmtinfo->depth) {
> > > + case 8:
> > > + unpack = UNICAM_PUM_UNPACK8;
> > > + break;
> > > + case 10:
> > > + unpack = UNICAM_PUM_UNPACK10;
> > > + break;
> > > + case 12:
> > > + unpack = UNICAM_PUM_UNPACK12;
> > > + break;
> > > + case 14:
> > > + unpack = UNICAM_PUM_UNPACK14;
> > > + break;
> > > + case 16:
> > > + unpack = UNICAM_PUM_UNPACK16;
> > > + break;
> > > + default:
> > > + unpack = UNICAM_PUM_NONE;
> > > + break;
> > > + }
> > > +
> > > + /* Repacking is always to 16bpp */
> > > + pack = UNICAM_PPM_PACK16;
> >
> > Also 8-bit data?
>
> Not that I know of. The 8-bit entries in unicam_image_formats have no
> .unpacked_fourcc field, so the condition in the if above will always be
> true for those as they can only be selected by setting the pixel format
> to fmtinfo->fourcc.
>
> > > + }
> > > +
> > > + val = 0;
> >
> > You could do initialisation in declaration.
>
> Yes, but I think it's more readable to keep all the code that affects
> the 'val' variable together.
>
> > > + unicam_set_field(&val, unpack, UNICAM_PUM_MASK);
> > > + unicam_set_field(&val, pack, UNICAM_PPM_MASK);
> > > + unicam_reg_write(unicam, UNICAM_IPIPE, val);
> > > +}
> > > +
> > > +static void unicam_cfg_image_id(struct unicam_device *unicam)
> > > +{
> > > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > +
> > > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > + /* CSI2 mode, hardcode VC 0 for now. */
> > > + unicam_reg_write(unicam, UNICAM_IDI0,
> > > + (0 << 6) | node->fmtinfo->csi_dt);
> > > + } else {
> > > + /* CCP2 mode */
> > > + unicam_reg_write(unicam, UNICAM_IDI0,
> > > + 0x80 | node->fmtinfo->csi_dt);
> > > + }
> > > +}
> > > +
> > > +static void unicam_enable_ed(struct unicam_device *unicam)
> > > +{
> > > + u32 val = unicam_reg_read(unicam, UNICAM_DCS);
> > > +
> > > + unicam_set_field(&val, 2, UNICAM_EDL_MASK);
> > > + /* Do not wrap at the end of the embedded data buffer */
> > > + unicam_set_field(&val, 0, UNICAM_DBOB);
> > > +
> > > + unicam_reg_write(unicam, UNICAM_DCS, val);
> > > +}
> > > +
> > > +static void unicam_start_rx(struct unicam_device *unicam,
> > > + struct unicam_buffer *buf)
> > > +{
> > > + struct unicam_node *node = &unicam->node[UNICAM_IMAGE_NODE];
> > > + int line_int_freq = node->fmt.fmt.pix.height >> 2;
> > > + unsigned int i;
> > > + u32 val;
> > > +
> > > + if (line_int_freq < 128)
> > > + line_int_freq = 128;
> >
> > line_int_freq = max(line_int_freq, 128);
> Ack.
>
> > > +
> > > + /* Enable lane clocks */
> > > + val = 1;
> >
> > Initialise in the loop initialisation below, I'd say.
>
> How about
>
> val = 0x55 & GENMASK(unicam->pipe.num_data_lanes * 2 - 1, 0);
I meant
val = 0x155 & GENMASK(unicam->pipe.num_data_lanes * 2 + 1, 0);
Maybe a comment would be useful ?
/*
* Enable lane clocks. The register is structured as follows:
*
* [9:8] - DAT3
* [7:6] - DAT2
* [5:4] - DAT1
* [3:2] - DAT0
* [1:0] - CLK
*
* Enabled lane must be set to b01, and disabled lanes to b00. The clock
* lane is always enabled.
*/
val = 0x155 & GENMASK(unicam->pipe.num_data_lanes * 2 + 1, 0);
> > > + for (i = 0; i < unicam->active_data_lanes; i++)
> > > + val = val << 2 | 1;
> > > + unicam_clk_write(unicam, val);
> > > +
> > > + /* Basic init */
> > > + unicam_reg_write(unicam, UNICAM_CTRL, UNICAM_MEM);
> > > +
> > > + /* Enable analogue control, and leave in reset. */
> > > + val = UNICAM_AR;
> > > + unicam_set_field(&val, 7, UNICAM_CTATADJ_MASK);
> > > + unicam_set_field(&val, 7, UNICAM_PTATADJ_MASK);
> > > + unicam_reg_write(unicam, UNICAM_ANA, val);
> > > + usleep_range(1000, 2000);
> > > +
> > > + /* Come out of reset */
> > > + unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_AR);
> > > +
> > > + /* Peripheral reset */
> > > + unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPR);
> > > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPR);
> > > +
> > > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_CPE);
> > > +
> > > + /* Enable Rx control. */
> > > + val = unicam_reg_read(unicam, UNICAM_CTRL);
> > > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > + unicam_set_field(&val, UNICAM_CPM_CSI2, UNICAM_CPM_MASK);
> > > + unicam_set_field(&val, UNICAM_DCM_STROBE, UNICAM_DCM_MASK);
> > > + } else {
> > > + unicam_set_field(&val, UNICAM_CPM_CCP2, UNICAM_CPM_MASK);
> > > + unicam_set_field(&val, unicam->bus_flags, UNICAM_DCM_MASK);
> > > + }
> > > + /* Packet framer timeout */
> > > + unicam_set_field(&val, 0xf, UNICAM_PFT_MASK);
> > > + unicam_set_field(&val, 128, UNICAM_OET_MASK);
> > > + unicam_reg_write(unicam, UNICAM_CTRL, val);
> > > +
> > > + unicam_reg_write(unicam, UNICAM_IHWIN, 0);
> > > + unicam_reg_write(unicam, UNICAM_IVWIN, 0);
> > > +
> > > + /* AXI bus access QoS setup */
> > > + val = unicam_reg_read(unicam, UNICAM_PRI);
> > > + unicam_set_field(&val, 0, UNICAM_BL_MASK);
> > > + unicam_set_field(&val, 0, UNICAM_BS_MASK);
> > > + unicam_set_field(&val, 0xe, UNICAM_PP_MASK);
> > > + unicam_set_field(&val, 8, UNICAM_NP_MASK);
> > > + unicam_set_field(&val, 2, UNICAM_PT_MASK);
> > > + unicam_set_field(&val, 1, UNICAM_PE);
> > > + unicam_reg_write(unicam, UNICAM_PRI, val);
> > > +
> > > + unicam_reg_write_field(unicam, UNICAM_ANA, 0, UNICAM_DDL);
> > > +
> > > + /* Always start in trigger frame capture mode (UNICAM_FCM set) */
> > > + val = UNICAM_FSIE | UNICAM_FEIE | UNICAM_FCM | UNICAM_IBOB;
> > > + unicam_set_field(&val, line_int_freq, UNICAM_LCIE_MASK);
> > > + unicam_reg_write(unicam, UNICAM_ICTL, val);
> > > + unicam_reg_write(unicam, UNICAM_STA, UNICAM_STA_MASK_ALL);
> > > + unicam_reg_write(unicam, UNICAM_ISTA, UNICAM_ISTA_MASK_ALL);
> > > +
> > > + /* tclk_term_en */
> > > + unicam_reg_write_field(unicam, UNICAM_CLT, 2, UNICAM_CLT1_MASK);
> > > + /* tclk_settle */
> > > + unicam_reg_write_field(unicam, UNICAM_CLT, 6, UNICAM_CLT2_MASK);
> > > + /* td_term_en */
> > > + unicam_reg_write_field(unicam, UNICAM_DLT, 2, UNICAM_DLT1_MASK);
> > > + /* ths_settle */
> > > + unicam_reg_write_field(unicam, UNICAM_DLT, 6, UNICAM_DLT2_MASK);
> > > + /* trx_enable */
> > > + unicam_reg_write_field(unicam, UNICAM_DLT, 0, UNICAM_DLT3_MASK);
> > > +
> > > + unicam_reg_write_field(unicam, UNICAM_CTRL, 0, UNICAM_SOE);
> > > +
> > > + /* Packet compare setup - required to avoid missing frame ends */
> > > + val = 0;
> > > + unicam_set_field(&val, 1, UNICAM_PCE);
> > > + unicam_set_field(&val, 1, UNICAM_GI);
> > > + unicam_set_field(&val, 1, UNICAM_CPH);
> > > + unicam_set_field(&val, 0, UNICAM_PCVC_MASK);
> > > + unicam_set_field(&val, 1, UNICAM_PCDT_MASK);
> > > + unicam_reg_write(unicam, UNICAM_CMP0, val);
> > > +
> > > + /* Enable clock lane and set up terminations */
> > > + val = 0;
> > > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > + /* CSI2 */
> > > + unicam_set_field(&val, 1, UNICAM_CLE);
> > > + unicam_set_field(&val, 1, UNICAM_CLLPE);
> > > + if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > > + unicam_set_field(&val, 1, UNICAM_CLTRE);
> > > + unicam_set_field(&val, 1, UNICAM_CLHSE);
> > > + }
> > > + } else {
> > > + /* CCP2 */
> > > + unicam_set_field(&val, 1, UNICAM_CLE);
> > > + unicam_set_field(&val, 1, UNICAM_CLHSE);
> > > + unicam_set_field(&val, 1, UNICAM_CLTRE);
> > > + }
> > > + unicam_reg_write(unicam, UNICAM_CLK, val);
> > > +
> > > + /*
> > > + * Enable required data lanes with appropriate terminations.
> > > + * The same value needs to be written to UNICAM_DATn registers for
> > > + * the active lanes, and 0 for inactive ones.
> > > + */
> > > + val = 0;
> > > + if (unicam->bus_type == V4L2_MBUS_CSI2_DPHY) {
> > > + /* CSI2 */
> > > + unicam_set_field(&val, 1, UNICAM_DLE);
> > > + unicam_set_field(&val, 1, UNICAM_DLLPE);
> > > + if (!(unicam->bus_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK)) {
> > > + unicam_set_field(&val, 1, UNICAM_DLTRE);
> > > + unicam_set_field(&val, 1, UNICAM_DLHSE);
> > > + }
> > > + } else {
> > > + /* CCP2 */
> > > + unicam_set_field(&val, 1, UNICAM_DLE);
> > > + unicam_set_field(&val, 1, UNICAM_DLHSE);
> > > + unicam_set_field(&val, 1, UNICAM_DLTRE);
> > > + }
> > > + unicam_reg_write(unicam, UNICAM_DAT0, val);
> > > +
> > > + if (unicam->active_data_lanes == 1)
> > > + val = 0;
> > > + unicam_reg_write(unicam, UNICAM_DAT1, val);
> > > +
> > > + if (unicam->max_data_lanes > 2) {
> > > + /*
> > > + * Registers UNICAM_DAT2 and UNICAM_DAT3 only valid if the
> > > + * instance supports more than 2 data lanes.
> > > + */
> > > + if (unicam->active_data_lanes == 2)
> > > + val = 0;
> > > + unicam_reg_write(unicam, UNICAM_DAT2, val);
> > > +
> > > + if (unicam->active_data_lanes == 3)
> > > + val = 0;
> > > + unicam_reg_write(unicam, UNICAM_DAT3, val);
> > > + }
> > > +
> > > + unicam_reg_write(unicam, UNICAM_IBLS,
> > > + node->fmt.fmt.pix.bytesperline);
> > > + unicam_wr_dma_addr(&unicam->node[UNICAM_IMAGE_NODE], buf);
> > > + unicam_set_packing_config(unicam);
> > > + unicam_cfg_image_id(unicam);
> > > +
> > > + val = unicam_reg_read(unicam, UNICAM_MISC);
> > > + unicam_set_field(&val, 1, UNICAM_FL0);
> > > + unicam_set_field(&val, 1, UNICAM_FL1);
> > > + unicam_reg_write(unicam, UNICAM_MISC, val);
> > > +
> > > + /* Enable peripheral */
> > > + unicam_reg_write_field(unicam, UNICAM_CTRL, 1, UNICAM_CPE);
> > > +
> > > + /* Load image pointers */
> > > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_LIP_MASK);
> > > +
> > > + /*
> > > + * Enable trigger only for the first frame to
> > > + * sync correctly to the FS from the source.
> > > + */
> > > + unicam_reg_write_field(unicam, UNICAM_ICTL, 1, UNICAM_TFC);
> > > +}
>
> [snip]
>
> > > +static int unicam_async_nf_init(struct unicam_device *unicam)
> > > +{
> > > + struct v4l2_fwnode_endpoint ep = { };
> >
> > If the bus-type property is mandatory and you have no stated defaults
> > anywhere, this is fine. I.e. all the relevant properties would need to be
> > mandatory.
>
> They are, as far as I can tell (well, the clock-noncontinuous property
> is not mandatory, but that's expected as it's a flag).
>
> > > + struct fwnode_handle *ep_handle;
> > > + struct v4l2_async_connection *asc;
> > > + int ret;
> > > +
> > > + ret = of_property_read_u32(unicam->dev->of_node, "brcm,num-data-lanes",
> > > + &unicam->max_data_lanes);
> > > + if (ret < 0) {
> > > + dev_err(unicam->dev, "Missing %s DT property\n",
> > > + "brcm,num-data-lanes");
> > > + return -EINVAL;
> > > + }
> > > +
> > > + /* Get and parse the local endpoint. */
> > > + ep_handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(unicam->dev), 0, 0,
> > > + FWNODE_GRAPH_ENDPOINT_NEXT);
> > > + if (!ep_handle) {
> > > + dev_err(unicam->dev, "No endpoint found\n");
> > > + return -ENODEV;
> > > + }
> > > +
> > > + ret = v4l2_fwnode_endpoint_parse(ep_handle, &ep);
> > > + if (ret) {
> > > + dev_err(unicam->dev, "Failed to parse endpoint: %d\n", ret);
> > > + goto error;
> > > + }
> > > +
> > > + unicam->bus_type = ep.bus_type;
> > > +
> > > + switch (ep.bus_type) {
> > > + case V4L2_MBUS_CSI2_DPHY: {
> > > + unsigned int num_data_lanes = ep.bus.mipi_csi2.num_data_lanes;
> > > +
> > > + if (num_data_lanes != 1 && num_data_lanes != 2 &&
> > > + num_data_lanes != 4) {
> > > + dev_err(unicam->dev, "%u data lanes not supported\n",
> > > + num_data_lanes);
> > > + goto error;
> > > + }
> > > +
> > > + if (num_data_lanes > unicam->max_data_lanes) {
> > > + dev_err(unicam->dev,
> > > + "Endpoint uses %u data lanes when %u are supported\n",
> > > + num_data_lanes, unicam->max_data_lanes);
> > > + goto error;
> > > + }
> > > +
> > > + unicam->active_data_lanes = num_data_lanes;
> > > + unicam->bus_flags = ep.bus.mipi_csi2.flags;
> > > + break;
> > > + }
> > > +
> > > + case V4L2_MBUS_CCP2:
> > > + unicam->max_data_lanes = 1;
> > > + unicam->active_data_lanes = 1;
> > > + unicam->bus_flags = ep.bus.mipi_csi1.strobe;
> > > + break;
> > > +
> > > + default:
> > > + /* Unsupported bus type */
> > > + dev_err(unicam->dev, "Unsupported bus type %u\n", ep.bus_type);
> > > + goto error;
> > > + }
> > > +
> > > + /* Initialize and register the async notifier. */
> > > + v4l2_async_nf_init(&unicam->notifier, &unicam->v4l2_dev);
> > > +
> > > + asc = v4l2_async_nf_add_fwnode_remote(&unicam->notifier, ep_handle,
> > > + struct v4l2_async_connection);
> > > + fwnode_handle_put(ep_handle);
> > > + ep_handle = NULL;
> > > +
> > > + if (IS_ERR(asc)) {
> > > + ret = PTR_ERR(asc);
> > > + dev_err(unicam->dev, "Failed to add entry to notifier: %d\n",
> > > + ret);
> > > + goto error;
> > > + }
> > > +
> > > + unicam->notifier.ops = &unicam_async_ops;
> > > +
> > > + ret = v4l2_async_nf_register(&unicam->notifier);
> > > + if (ret) {
> > > + dev_err(unicam->dev, "Error registering device notifier: %d\n",
> > > + ret);
> > > + goto error;
> > > + }
> > > +
> > > + return 0;
> > > +
> > > +error:
> > > + fwnode_handle_put(ep_handle);
> > > + return ret;
> > > +}
> > > +
> > > +/* -----------------------------------------------------------------------------
> > > + * Probe & remove
> > > + */
> > > +
> > > +static int unicam_media_init(struct unicam_device *unicam)
> > > +{
> > > + int ret;
> > > +
> > > + unicam->mdev.dev = unicam->dev;
> > > + strscpy(unicam->mdev.model, UNICAM_MODULE_NAME,
> > > + sizeof(unicam->mdev.model));
> > > + strscpy(unicam->mdev.serial, "", sizeof(unicam->mdev.serial));
> >
> > Isn't the field already zeroed?
>
> Indeed. I'll drop this.
>
> >
> > > + unicam->mdev.hw_revision = 0;
> > > +
> > > + media_device_init(&unicam->mdev);
> > > +
> > > + unicam->v4l2_dev.mdev = &unicam->mdev;
> > > +
> > > + ret = v4l2_device_register(unicam->dev, &unicam->v4l2_dev);
> > > + if (ret < 0) {
> > > + dev_err(unicam->dev, "Unable to register v4l2 device\n");
> > > + goto err_media_cleanup;
> > > + }
> > > +
> > > + ret = media_device_register(&unicam->mdev);
> > > + if (ret < 0) {
> > > + dev_err(unicam->dev,
> > > + "Unable to register media-controller device\n");
> > > + goto err_v4l2_unregister;
> > > + }
> > > +
> > > + return 0;
> > > +
> > > +err_v4l2_unregister:
> > > + v4l2_device_unregister(&unicam->v4l2_dev);
> > > +err_media_cleanup:
> > > + media_device_cleanup(&unicam->mdev);
> > > + return ret;
> > > +}
>
> [snip]
--
Regards,
Laurent Pinchart
^ permalink raw reply
* Re: [PATCH] of: property: fw_devlink: Fix stupid bug in remote-endpoint parsing
From: John Watts @ 2024-03-26 2:31 UTC (permalink / raw)
To: Saravana Kannan
Cc: Rob Herring, Frank Rowand, Hervé Codina, Luca Ceresoli,
kernel-team, Rob Herring, devicetree, linux-kernel
In-Reply-To: <CAGETcx-Emvu41nB3UDnb4Gh2aJEKu_hFcHX89uWnBTnaqvpN8g@mail.gmail.com>
Hello again,
On Mon, Mar 25, 2024 at 06:35:45PM -0700, Saravana Kannan wrote:
> Ok, I have a solution. Have the audio-graph-card2 find the fwnode of
> "multi" and mark it as "not a device" by doing something like this in
> the driver. That should help fw_devlink handle this correctly.
>
> fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
I have done this:
struct device_node *node = dev->of_node;
struct device_node *node2;
node2 = of_get_child_by_name(node, "multi");
printk("node2 %pOF %pfw %x\n", node2, node2->fwnode, node2->fwnode.flags);
node2->fwnode.flags |= FWNODE_FLAG_NOT_DEVICE;
of_node_put(node2);
This doesn't do anything, but this does:
struct device_node *node = dev->of_node;
struct device_node *node2;
node2 = of_get_child_by_name(node, "multi");
fw_devlink_purge_absent_suppliers(&node2->fwnode);
printk("node2 %pOF %pfw %x\n", node2, node2->fwnode, node2->fwnode.flags);
of_node_put(node2);
Should I be using fw_devlink_purge_absent_suppliers?
> -Saravana
John.
^ permalink raw reply
* [PATCH 0/2] riscv: sophgo: add support for usb controller of CV18XX/SG200X
From: Inochi Amaoto @ 2024-03-26 2:36 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
linux-kernel, linux-riscv
Add usb controller params for the DWC2 USB ip in CV18XX/SG200X
Inochi Amaoto (2):
dt-bindings: usb: dwc2: Add support for Sophgo CV18XX/SG200X series
SoC
usb: dwc2: add support for Sophgo CV18XX/SG200X series SoC
.../devicetree/bindings/usb/dwc2.yaml | 1 +
drivers/usb/dwc2/params.c | 21 +++++++++++++++++++
2 files changed, 22 insertions(+)
--
2.44.0
^ permalink raw reply
* [PATCH 1/2] dt-bindings: usb: dwc2: Add support for Sophgo CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26 2:37 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB49537ED844CEBF19880326CEBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
Add compatible string for the DWC2 IP which is used by
Sophgo CV18XX/SG2000 series SoC.
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
Documentation/devicetree/bindings/usb/dwc2.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml
index 0a5c98ea711d..9a2106e7b4b6 100644
--- a/Documentation/devicetree/bindings/usb/dwc2.yaml
+++ b/Documentation/devicetree/bindings/usb/dwc2.yaml
@@ -59,6 +59,7 @@ properties:
- const: amcc,dwc-otg
- const: apm,apm82181-dwc-otg
- const: snps,dwc2
+ - const: sophgo,cv1800-usb
- const: st,stm32f4x9-fsotg
- const: st,stm32f4x9-hsotg
- const: st,stm32f7-hsotg
--
2.44.0
^ permalink raw reply related
* [PATCH 2/2] usb: dwc2: add support for Sophgo CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26 2:37 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Minas Harutyunyan, Paul Walmsley, Palmer Dabbelt,
Albert Ou
Cc: Chen Wang, Liu Gui, Inochi Amaoto, linux-usb, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB49537ED844CEBF19880326CEBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
Add params for DWC2 IP in Sophgo CV18XX/SG200X series SoC.
Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
---
drivers/usb/dwc2/params.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c
index eb677c3cfd0b..171fcb34eb75 100644
--- a/drivers/usb/dwc2/params.c
+++ b/drivers/usb/dwc2/params.c
@@ -201,6 +201,25 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
}
+static void dwc2_set_cv1800_params(struct dwc2_hsotg *hsotg)
+{
+ struct dwc2_core_params *p = &hsotg->params;
+
+ p->otg_caps.hnp_support = false;
+ p->otg_caps.srp_support = false;
+ p->host_dma = false;
+ p->g_dma = false;
+ p->speed = DWC2_SPEED_PARAM_HIGH;
+ p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
+ p->phy_utmi_width = 16;
+ p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
+ p->lpm = false;
+ p->lpm_clock_gating = false;
+ p->besl = false;
+ p->hird_threshold_en = false;
+ p->power_down = DWC2_POWER_DOWN_PARAM_NONE;
+}
+
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
@@ -295,6 +314,8 @@ const struct of_device_id dwc2_of_match_table[] = {
.data = dwc2_set_amlogic_a1_params },
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
{ .compatible = "apm,apm82181-dwc-otg", .data = dwc2_set_amcc_params },
+ { .compatible = "sophgo,cv1800-usb",
+ .data = dwc2_set_cv1800_params },
{ .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" },
--
2.44.0
^ permalink raw reply related
* [PATCH v2 0/6] PCI: dwc: rcar-gen4: Add R-Car V4H support
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
The pcie-rcar-gen4 driver can reuse other R-Car Gen4 support. However,
some initializing settings differs between R-Car S4-8 (r8a779f0) and
others. The R-Car S4-8 will be minority about the setting way. So,
R-Car V4H will be majority and this is generic initialization way
as "renesas,rcar-gen4-pcie{-ep}" compatible. For now, I tested
both R-Car S4-8 and R-Car V4H on this driver. I'll support one more
other SoC (R-Car V4M) in the future.
Changes from v1:
https://lore.kernel.org/linux-pci/20240229120719.2553638-1-yoshihiro.shimoda.uh@renesas.com/
- Based on v6.9-rc1.
- Add Acked-by and/or Reviewed-by in patch [126/6].
Yoshihiro Shimoda (6):
dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
PCI: dwc: rcar-gen4: Add a new function pointer for other SoC support
PCI: dwc: rcar-gen4: Add support for other R-Car Gen4 PCIe controller
misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
.../bindings/pci/rcar-gen4-pci-ep.yaml | 4 +-
.../bindings/pci/rcar-gen4-pci-host.yaml | 4 +-
drivers/misc/pci_endpoint_test.c | 4 +
drivers/pci/controller/dwc/pcie-designware.h | 6 +
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 245 +++++++++++++++++-
5 files changed, 255 insertions(+), 8 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH v2 1/6] dt-bindings: PCI: rcar-gen4-pci-host: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
Document bindings for R-Car V4H (R8A779G0) PCIe host module.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
index ffb34339b637..955c664f1fbb 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-host.yaml
@@ -16,7 +16,9 @@ allOf:
properties:
compatible:
items:
- - const: renesas,r8a779f0-pcie # R-Car S4-8
+ - enum:
+ - renesas,r8a779f0-pcie # R-Car S4-8
+ - renesas,r8a779g0-pcie # R-Car V4H
- const: renesas,rcar-gen4-pcie # R-Car Gen4
reg:
--
2.25.1
^ permalink raw reply related
* [PATCH v2 3/6] PCI: dwc: Add PCIE_PORT_{FORCE,LANE_SKEW} macros
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
R-Car Gen4 PCIe controller needs to use the Synopsys-specific PCIe
configuration registers. So, add the macros.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-designware.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 26dae4837462..aa4db6eaf02a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -71,6 +71,9 @@
#define LINK_WAIT_IATU 9
/* Synopsys-specific PCIe configuration registers */
+#define PCIE_PORT_FORCE 0x708
+#define PORT_FORCE_DO_DESKEW_FOR_SRIS BIT(23)
+
#define PCIE_PORT_AFR 0x70C
#define PORT_AFR_N_FTS_MASK GENMASK(15, 8)
#define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
@@ -92,6 +95,9 @@
#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
+#define PCIE_PORT_LANE_SKEW 0x714
+#define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)
+
#define PCIE_PORT_DEBUG0 0x728
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
--
2.25.1
^ permalink raw reply related
* [PATCH v2 2/6] dt-bindings: PCI: rcar-gen4-pci-ep: Add R-Car V4H compatible
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Conor Dooley, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
Document bindings for R-Car V4H (R8A779G0) PCIe endpoint module.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
index fe38f62da066..91b81ac75592 100644
--- a/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
+++ b/Documentation/devicetree/bindings/pci/rcar-gen4-pci-ep.yaml
@@ -16,7 +16,9 @@ allOf:
properties:
compatible:
items:
- - const: renesas,r8a779f0-pcie-ep # R-Car S4-8
+ - enum:
+ - renesas,r8a779f0-pcie-ep # R-Car S4-8
+ - renesas,r8a779g0-pcie-ep # R-Car V4H
- const: renesas,rcar-gen4-pcie-ep # R-Car Gen4
reg:
--
2.25.1
^ permalink raw reply related
* [PATCH v2 4/6] PCI: dwc: rcar-gen4: Add a new function pointer for other SoC support
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
This driver can reuse other R-Car Gen4 SoC support. However, some
initializing settings differs between r8a779f0 and others. So, add
a new function pointer start_link_enable() to support other R-Car
Gen4 SoC in the future. No behavior changes.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 57 +++++++++++++++++++--
1 file changed, 52 insertions(+), 5 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 0be760ed420b..a37613dd9ff4 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -53,9 +53,16 @@ struct rcar_gen4_pcie {
void __iomem *base;
struct platform_device *pdev;
enum dw_pcie_device_mode mode;
+
+ int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
+struct rcar_gen4_pcie_platdata {
+ enum dw_pcie_device_mode mode;
+ int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+};
+
/* Common */
static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
bool enable)
@@ -123,9 +130,13 @@ static int rcar_gen4_pcie_speed_change(struct dw_pcie *dw)
static int rcar_gen4_pcie_start_link(struct dw_pcie *dw)
{
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
- int i, changes;
+ int i, changes, ret;
- rcar_gen4_pcie_ltssm_enable(rcar, true);
+ if (rcar->start_link_enable) {
+ ret = rcar->start_link_enable(rcar);
+ if (ret)
+ return ret;
+ }
/*
* Require direct speed change with retrying here if the link_gen is
@@ -437,7 +448,10 @@ static void rcar_gen4_remove_dw_pcie_ep(struct rcar_gen4_pcie *rcar)
/* Common */
static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
{
- rcar->mode = (uintptr_t)of_device_get_match_data(&rcar->pdev->dev);
+ const struct rcar_gen4_pcie_platdata *pd = of_device_get_match_data(&rcar->pdev->dev);
+
+ rcar->mode = pd->mode;
+ rcar->start_link_enable = pd->start_link_enable;
switch (rcar->mode) {
case DW_PCIE_RC_TYPE:
@@ -500,14 +514,47 @@ static void rcar_gen4_pcie_remove(struct platform_device *pdev)
rcar_gen4_pcie_unprepare(rcar);
}
+static int r8a779f0_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
+{
+ rcar_gen4_pcie_ltssm_enable(rcar, true);
+
+ return 0;
+}
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
+ .mode = DW_PCIE_RC_TYPE,
+ .start_link_enable = r8a779f0_pcie_start_link_enable,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
+ .mode = DW_PCIE_EP_TYPE,
+ .start_link_enable = r8a779f0_pcie_start_link_enable,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
+ .mode = DW_PCIE_RC_TYPE,
+};
+
+static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
+ .mode = DW_PCIE_EP_TYPE,
+};
+
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
+ {
+ .compatible = "renesas,r8a779f0-pcie",
+ .data = &platdata_r8a779f0_pcie,
+ },
+ {
+ .compatible = "renesas,r8a779f0-pcie-ep",
+ .data = &platdata_r8a779f0_pcie_ep,
+ },
{
.compatible = "renesas,rcar-gen4-pcie",
- .data = (void *)DW_PCIE_RC_TYPE,
+ .data = &platdata_rcar_gen4_pcie,
},
{
.compatible = "renesas,rcar-gen4-pcie-ep",
- .data = (void *)DW_PCIE_EP_TYPE,
+ .data = &platdata_rcar_gen4_pcie_ep,
},
{},
};
--
2.25.1
^ permalink raw reply related
* [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
can be used for testing PCIe EP on R-Car V4H.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/misc/pci_endpoint_test.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index c38a6083f0a7..2fa3c6473c7d 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -83,6 +83,7 @@
#define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
#define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
#define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
+#define PCI_DEVICE_ID_RENESAS_R8A779G0 0x0030
static DEFINE_IDA(pci_endpoint_test_ida);
@@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
.driver_data = (kernel_ulong_t)&default_data,
},
+ { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
+ .driver_data = (kernel_ulong_t)&default_data,
+ },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
.driver_data = (kernel_ulong_t)&j721e_data,
},
--
2.25.1
^ permalink raw reply related
* [PATCH v2 5/6] PCI: dwc: rcar-gen4: Add support for other R-Car Gen4 PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26 2:45 UTC (permalink / raw)
To: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani
Cc: marek.vasut+renesas, linux-pci, devicetree, linux-renesas-soc,
Yoshihiro Shimoda
In-Reply-To: <20240326024540.2336155-1-yoshihiro.shimoda.uh@renesas.com>
The PCIe controllers of R-Car V4H (r8a779g0) and one more SoC require
different initializing settings than R-Car S4-8 (r8a779f0). So, add
specific functions for them as "renesas,rcar-gen4-pcie{-ep}" compatible.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 188 +++++++++++++++++++-
1 file changed, 187 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index a37613dd9ff4..7f3b5e9ca405 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -5,8 +5,10 @@
*/
#include <linux/delay.h>
+#include <linux/firmware.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pci.h>
@@ -20,9 +22,10 @@
/* Renesas-specific */
/* PCIe Mode Setting Register 0 */
#define PCIEMSR0 0x0000
-#define BIFUR_MOD_SET_ON BIT(0)
+#define APP_SRIS_MODE BIT(6)
#define DEVICE_TYPE_EP 0
#define DEVICE_TYPE_RC BIT(4)
+#define BIFUR_MOD_SET_ON BIT(0)
/* PCIe Interrupt Status 0 */
#define PCIEINTSTS0 0x0084
@@ -37,33 +40,179 @@
#define PCIEDMAINTSTSEN 0x0314
#define PCIEDMAINTSTSEN_INIT GENMASK(15, 0)
+/* Port Logic Registers 89 */
+#define PRTLGC89 0x0b70
+
+/* Port Logic Registers 90 */
+#define PRTLGC90 0x0b74
+
/* PCIe Reset Control Register 1 */
#define PCIERSTCTRL1 0x0014
#define APP_HOLD_PHY_RST BIT(16)
#define APP_LTSSM_ENABLE BIT(0)
+/* PCIe Power Management Control */
+#define PCIEPWRMNGCTRL 0x0070
+#define APP_CLK_REQ_N BIT(11)
+#define APP_CLK_PM_EN BIT(10)
+
#define RCAR_NUM_SPEED_CHANGE_RETRIES 10
#define RCAR_MAX_LINK_SPEED 4
#define RCAR_GEN4_PCIE_EP_FUNC_DBI_OFFSET 0x1000
#define RCAR_GEN4_PCIE_EP_FUNC_DBI2_OFFSET 0x800
+#define RCAR_GEN4_PCIE_FIRMEARE_NAME "rcar_gen4_pcie.bin"
+#define RCAR_GEN4_PCIE_FIRMEARE_BASE_ADDR 0xc000
+
struct rcar_gen4_pcie {
struct dw_pcie dw;
void __iomem *base;
+ /*
+ * The R-Car Gen4 documents don't describe the PHY registers' name.
+ * But, the initialization procedure describes these offsets. So,
+ * this driver has "phy_base + magical offset number" for it.
+ */
+ void __iomem *phy_base;
struct platform_device *pdev;
enum dw_pcie_device_mode mode;
int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+ void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
struct rcar_gen4_pcie_platdata {
enum dw_pcie_device_mode mode;
int (*start_link_enable)(struct rcar_gen4_pcie *rcar);
+ void (*additional_common_init)(struct rcar_gen4_pcie *rcar);
};
/* Common */
+static void rcar_gen4_pcie_phy_reg_update_bits(struct rcar_gen4_pcie *rcar,
+ u32 offset, u32 mask, u32 val)
+{
+ u32 tmp;
+
+ tmp = readl(rcar->phy_base + offset);
+ tmp &= ~mask;
+ tmp |= val;
+ writel(tmp, rcar->phy_base + offset);
+}
+
+static int rcar_gen4_pcie_reg_check_bit(struct rcar_gen4_pcie *rcar,
+ u32 offset, u32 mask)
+{
+ struct dw_pcie *dw = &rcar->dw;
+
+ if (dw_pcie_readl_dbi(dw, offset) & mask)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int rcar_gen4_pcie_update_phy_firmware(struct rcar_gen4_pcie *rcar)
+{
+ const u32 check_addr[] = { 0x00101018, 0x00101118, 0x00101021, 0x00101121};
+ struct dw_pcie *dw = &rcar->dw;
+ const struct firmware *fw;
+ unsigned int i, timeout;
+ u32 data;
+ int ret;
+
+ ret = request_firmware(&fw, RCAR_GEN4_PCIE_FIRMEARE_NAME, dw->dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < (fw->size / 2); i++) {
+ data = fw->data[i * 2] | fw->data[(i * 2) + 1] << 8;
+ timeout = 100;
+retry_data:
+ dw_pcie_writel_dbi(dw, PRTLGC89, RCAR_GEN4_PCIE_FIRMEARE_BASE_ADDR + i);
+ dw_pcie_writel_dbi(dw, PRTLGC90, data);
+ if (rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30)) < 0) {
+ if (!(--timeout)) {
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ usleep_range(100, 200);
+ goto retry_data;
+ }
+ }
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(17), BIT(17));
+
+ for (i = 0; i < ARRAY_SIZE(check_addr); i++) {
+ timeout = 100;
+retry_check:
+ dw_pcie_writel_dbi(dw, PRTLGC89, check_addr[i]);
+ ret = rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC89, BIT(30));
+ ret |= rcar_gen4_pcie_reg_check_bit(rcar, PRTLGC90, BIT(0));
+ if (ret < 0) {
+ if (!(--timeout)) {
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+ usleep_range(100, 200);
+ goto retry_check;
+ }
+ }
+
+ ret = 0;
+exit:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int rcar_gen4_pcie_enable_phy(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 val;
+ int ret;
+
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_FORCE);
+ val |= PORT_FORCE_DO_DESKEW_FOR_SRIS;
+ dw_pcie_writel_dbi(dw, PCIE_PORT_FORCE, val);
+
+ val = readl(rcar->base + PCIEMSR0);
+ val |= APP_SRIS_MODE;
+ writel(val, rcar->base + PCIEMSR0);
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(28), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(20), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(12), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x700, BIT(4), 0);
+
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(23, 22), BIT(22));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(18, 16), GENMASK(17, 16));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(7, 6), BIT(6));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x148, GENMASK(2, 0), GENMASK(11, 0));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x1d4, GENMASK(16, 15), GENMASK(16, 15));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x514, BIT(26), BIT(26));
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(16), 0);
+ rcar_gen4_pcie_phy_reg_update_bits(rcar, 0x0f8, BIT(19), BIT(19));
+
+ val = readl(rcar->base + PCIERSTCTRL1);
+ val &= ~APP_HOLD_PHY_RST;
+ writel(val, rcar->base + PCIERSTCTRL1);
+
+ ret = readl_poll_timeout(rcar->phy_base + 0x0f8, val, !(val & BIT(18)),
+ 100, 10000);
+ if (ret < 0)
+ return ret;
+
+ ret = rcar_gen4_pcie_update_phy_firmware(rcar);
+ if (ret)
+ return ret;
+
+ val = readl(rcar->base + PCIERSTCTRL1);
+ val |= APP_LTSSM_ENABLE;
+ writel(val, rcar->base + PCIERSTCTRL1);
+
+ return 0;
+}
+
static void rcar_gen4_pcie_ltssm_enable(struct rcar_gen4_pcie *rcar,
bool enable)
{
@@ -201,6 +350,9 @@ static int rcar_gen4_pcie_common_init(struct rcar_gen4_pcie *rcar)
if (ret)
goto err_unprepare;
+ if (rcar->additional_common_init)
+ rcar->additional_common_init(rcar);
+
return 0;
err_unprepare:
@@ -242,6 +394,10 @@ static void rcar_gen4_pcie_unprepare(struct rcar_gen4_pcie *rcar)
static int rcar_gen4_pcie_get_resources(struct rcar_gen4_pcie *rcar)
{
+ rcar->phy_base = devm_platform_ioremap_resource_byname(rcar->pdev, "phy");
+ if (IS_ERR(rcar->phy_base))
+ return PTR_ERR(rcar->base);
+
/* Renesas-specific registers */
rcar->base = devm_platform_ioremap_resource_byname(rcar->pdev, "app");
@@ -452,6 +608,7 @@ static int rcar_gen4_add_dw_pcie(struct rcar_gen4_pcie *rcar)
rcar->mode = pd->mode;
rcar->start_link_enable = pd->start_link_enable;
+ rcar->additional_common_init = pd->additional_common_init;
switch (rcar->mode) {
case DW_PCIE_RC_TYPE:
@@ -521,6 +678,31 @@ static int r8a779f0_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
return 0;
}
+static int rcar_gen4_pcie_start_link_enable(struct rcar_gen4_pcie *rcar)
+{
+ return rcar_gen4_pcie_enable_phy(rcar);
+}
+
+static void rcar_gen4_pcie_additional_common_init(struct rcar_gen4_pcie *rcar)
+{
+ struct dw_pcie *dw = &rcar->dw;
+ u32 val;
+
+ /*
+ * The SoC manual said the register setting is required. Otherwise,
+ * linkup failed.
+ */
+ val = dw_pcie_readl_dbi(dw, PCIE_PORT_LANE_SKEW);
+ val &= ~PORT_LANE_SKEW_INSERT_MASK;
+ if (dw->num_lanes < 4)
+ val |= BIT(6);
+ dw_pcie_writel_dbi(dw, PCIE_PORT_LANE_SKEW, val);
+
+ val = readl(rcar->base + PCIEPWRMNGCTRL);
+ val |= APP_CLK_REQ_N | APP_CLK_PM_EN;
+ writel(val, rcar->base + PCIEPWRMNGCTRL);
+}
+
static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie = {
.mode = DW_PCIE_RC_TYPE,
.start_link_enable = r8a779f0_pcie_start_link_enable,
@@ -533,10 +715,14 @@ static struct rcar_gen4_pcie_platdata platdata_r8a779f0_pcie_ep = {
static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie = {
.mode = DW_PCIE_RC_TYPE,
+ .start_link_enable = rcar_gen4_pcie_start_link_enable,
+ .additional_common_init = rcar_gen4_pcie_additional_common_init,
};
static struct rcar_gen4_pcie_platdata platdata_rcar_gen4_pcie_ep = {
.mode = DW_PCIE_EP_TYPE,
+ .start_link_enable = rcar_gen4_pcie_start_link_enable,
+ .additional_common_init = rcar_gen4_pcie_additional_common_init,
};
static const struct of_device_id rcar_gen4_pcie_of_match[] = {
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Frank Li @ 2024-03-26 3:21 UTC (permalink / raw)
To: Yoshihiro Shimoda
Cc: lpieralisi, kw, robh, bhelgaas, krzysztof.kozlowski+dt, conor+dt,
jingoohan1, gustavo.pimentel, mani, marek.vasut+renesas,
linux-pci, devicetree, linux-renesas-soc, Geert Uytterhoeven
In-Reply-To: <20240326024540.2336155-7-yoshihiro.shimoda.uh@renesas.com>
On Tue, Mar 26, 2024 at 11:45:40AM +0900, Yoshihiro Shimoda wrote:
> Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
> can be used for testing PCIe EP on R-Car V4H.
>
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> ---
> drivers/misc/pci_endpoint_test.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index c38a6083f0a7..2fa3c6473c7d 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -83,6 +83,7 @@
> #define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
> #define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
> #define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
> +#define PCI_DEVICE_ID_RENESAS_R8A779G0 0x0030
>
> static DEFINE_IDA(pci_endpoint_test_ida);
>
> @@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
> { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
> .driver_data = (kernel_ulong_t)&default_data,
> },
> + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
> + .driver_data = (kernel_ulong_t)&default_data,
> + },
You use default_data, why need new device_id? I think you can use 0x0031
to do test.
Frank
> { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
> .driver_data = (kernel_ulong_t)&j721e_data,
> },
> --
> 2.25.1
>
^ permalink raw reply
* Re: [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Frank Li @ 2024-03-26 3:37 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <IA1PR20MB4953E2937788D9D92C91ABBBBB352@IA1PR20MB4953.namprd20.prod.outlook.com>
On Tue, Mar 26, 2024 at 09:47:03AM +0800, Inochi Amaoto wrote:
> The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
> an additional channel remap register located in the top system control
> area. The DMA channel is exclusive to each core.
>
> Add the dmamux binding for CV18XX/SG200X series SoC
>
> Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> ---
> .../bindings/dma/sophgo,cv1800-dmamux.yaml | 48 ++++++++++++++++
> include/dt-bindings/dma/cv1800-dma.h | 55 +++++++++++++++++++
I remember checkpatch.pl require .h have seperate patch.
Frank
> 2 files changed, 103 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> create mode 100644 include/dt-bindings/dma/cv1800-dma.h
>
> diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> new file mode 100644
> index 000000000000..d7256646ea26
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> @@ -0,0 +1,48 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sophgo CV1800/SG200 Series DMA mux
> +
> +maintainers:
> + - Inochi Amaoto <inochiama@outlook.com>
> +
> +allOf:
> + - $ref: dma-router.yaml#
> +
> +properties:
> + compatible:
> + const: sophgo,cv1800-dmamux
> +
> + reg:
> + items:
> + - description: DMA channal remapping register
> + - description: DMA channel interrupt mapping register
> +
Look like driver have not use it.
Frank
> + '#dma-cells':
> + const: 2
> + description:
> + The first cells is device id. The second one is the cpu id.
> +
> + dma-masters:
> + maxItems: 1
> +
> + dma-requests:
> + const: 8
> +
> +required:
> + - '#dma-cells'
> + - dma-masters
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + dma-router {
> + compatible = "sophgo,cv1800-dmamux";
> + #dma-cells = <2>;
> + dma-masters = <&dmac>;
> + dma-requests = <8>;
> + };
> diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
> new file mode 100644
> index 000000000000..3ce9dac25259
> --- /dev/null
> +++ b/include/dt-bindings/dma/cv1800-dma.h
> @@ -0,0 +1,55 @@
> +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> +
> +#ifndef __DT_BINDINGS_DMA_CV1800_H__
> +#define __DT_BINDINGS_DMA_CV1800_H__
> +
> +#define DMA_I2S0_RX 0
> +#define DMA_I2S0_TX 1
> +#define DMA_I2S1_RX 2
> +#define DMA_I2S1_TX 3
> +#define DMA_I2S2_RX 4
> +#define DMA_I2S2_TX 5
> +#define DMA_I2S3_RX 6
> +#define DMA_I2S3_TX 7
> +#define DMA_UART0_RX 8
> +#define DMA_UART0_TX 9
> +#define DMA_UART1_RX 10
> +#define DMA_UART1_TX 11
> +#define DMA_UART2_RX 12
> +#define DMA_UART2_TX 13
> +#define DMA_UART3_RX 14
> +#define DMA_UART3_TX 15
> +#define DMA_SPI0_RX 16
> +#define DMA_SPI0_TX 17
> +#define DMA_SPI1_RX 18
> +#define DMA_SPI1_TX 19
> +#define DMA_SPI2_RX 20
> +#define DMA_SPI2_TX 21
> +#define DMA_SPI3_RX 22
> +#define DMA_SPI3_TX 23
> +#define DMA_I2C0_RX 24
> +#define DMA_I2C0_TX 25
> +#define DMA_I2C1_RX 26
> +#define DMA_I2C1_TX 27
> +#define DMA_I2C2_RX 28
> +#define DMA_I2C2_TX 29
> +#define DMA_I2C3_RX 30
> +#define DMA_I2C3_TX 31
> +#define DMA_I2C4_RX 32
> +#define DMA_I2C4_TX 33
> +#define DMA_TDM0_RX 34
> +#define DMA_TDM0_TX 35
> +#define DMA_TDM1_RX 36
> +#define DMA_AUDSRC 37
> +#define DMA_SPI_NAND 38
> +#define DMA_SPI_NOR 39
> +#define DMA_UART4_RX 40
> +#define DMA_UART4_TX 41
> +#define DMA_SPI_NOR1 42
> +
> +#define DMA_CPU_A53 0
> +#define DMA_CPU_C906_0 1
> +#define DMA_CPU_C906_1 2
> +
> +
> +#endif // __DT_BINDINGS_DMA_CV1800_H__
> --
> 2.44.0
>
^ permalink raw reply
* Re: [PATCH v5 1/3] dt-bindings: dmaengine: Add dmamux for CV18XX/SG200X series SoC
From: Inochi Amaoto @ 2024-03-26 3:49 UTC (permalink / raw)
To: Frank Li, Inochi Amaoto
Cc: Vinod Koul, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen Wang, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Jisheng Zhang, Liu Gui, Jingbao Qiu, dlan, dmaengine, devicetree,
linux-kernel, linux-riscv
In-Reply-To: <ZgJDCL+aq3ZTE6/1@lizhi-Precision-Tower-5810>
On Mon, Mar 25, 2024 at 11:37:44PM -0400, Frank Li wrote:
> On Tue, Mar 26, 2024 at 09:47:03AM +0800, Inochi Amaoto wrote:
> > The DMA IP of Sophgo CV18XX/SG200X is based on a DW AXI CORE, with
> > an additional channel remap register located in the top system control
> > area. The DMA channel is exclusive to each core.
> >
> > Add the dmamux binding for CV18XX/SG200X series SoC
> >
> > Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> > ---
> > .../bindings/dma/sophgo,cv1800-dmamux.yaml | 48 ++++++++++++++++
> > include/dt-bindings/dma/cv1800-dma.h | 55 +++++++++++++++++++
>
> I remember checkpatch.pl require .h have seperate patch.
>
> Frank
checkpatch.pl does not give warning like this.
>
> > 2 files changed, 103 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> > create mode 100644 include/dt-bindings/dma/cv1800-dma.h
> >
> > diff --git a/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> > new file mode 100644
> > index 000000000000..d7256646ea26
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/dma/sophgo,cv1800-dmamux.yaml
> > @@ -0,0 +1,48 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/dma/sophgo,cv1800-dmamux.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Sophgo CV1800/SG200 Series DMA mux
> > +
> > +maintainers:
> > + - Inochi Amaoto <inochiama@outlook.com>
> > +
> > +allOf:
> > + - $ref: dma-router.yaml#
> > +
> > +properties:
> > + compatible:
> > + const: sophgo,cv1800-dmamux
> > +
> > + reg:
> > + items:
> > + - description: DMA channal remapping register
> > + - description: DMA channel interrupt mapping register
> > +
>
> Look like driver have not use it.
>
The driver uses syscon offset to access the registers. This dmamux is
a subdevice of syscon.
And this properity, suggested by Rob, is just used to keep DT complete.
> Frank
>
> > + '#dma-cells':
> > + const: 2
> > + description:
> > + The first cells is device id. The second one is the cpu id.
> > +
> > + dma-masters:
> > + maxItems: 1
> > +
> > + dma-requests:
> > + const: 8
> > +
> > +required:
> > + - '#dma-cells'
> > + - dma-masters
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + dma-router {
> > + compatible = "sophgo,cv1800-dmamux";
> > + #dma-cells = <2>;
> > + dma-masters = <&dmac>;
> > + dma-requests = <8>;
> > + };
> > diff --git a/include/dt-bindings/dma/cv1800-dma.h b/include/dt-bindings/dma/cv1800-dma.h
> > new file mode 100644
> > index 000000000000..3ce9dac25259
> > --- /dev/null
> > +++ b/include/dt-bindings/dma/cv1800-dma.h
> > @@ -0,0 +1,55 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause */
> > +
> > +#ifndef __DT_BINDINGS_DMA_CV1800_H__
> > +#define __DT_BINDINGS_DMA_CV1800_H__
> > +
> > +#define DMA_I2S0_RX 0
> > +#define DMA_I2S0_TX 1
> > +#define DMA_I2S1_RX 2
> > +#define DMA_I2S1_TX 3
> > +#define DMA_I2S2_RX 4
> > +#define DMA_I2S2_TX 5
> > +#define DMA_I2S3_RX 6
> > +#define DMA_I2S3_TX 7
> > +#define DMA_UART0_RX 8
> > +#define DMA_UART0_TX 9
> > +#define DMA_UART1_RX 10
> > +#define DMA_UART1_TX 11
> > +#define DMA_UART2_RX 12
> > +#define DMA_UART2_TX 13
> > +#define DMA_UART3_RX 14
> > +#define DMA_UART3_TX 15
> > +#define DMA_SPI0_RX 16
> > +#define DMA_SPI0_TX 17
> > +#define DMA_SPI1_RX 18
> > +#define DMA_SPI1_TX 19
> > +#define DMA_SPI2_RX 20
> > +#define DMA_SPI2_TX 21
> > +#define DMA_SPI3_RX 22
> > +#define DMA_SPI3_TX 23
> > +#define DMA_I2C0_RX 24
> > +#define DMA_I2C0_TX 25
> > +#define DMA_I2C1_RX 26
> > +#define DMA_I2C1_TX 27
> > +#define DMA_I2C2_RX 28
> > +#define DMA_I2C2_TX 29
> > +#define DMA_I2C3_RX 30
> > +#define DMA_I2C3_TX 31
> > +#define DMA_I2C4_RX 32
> > +#define DMA_I2C4_TX 33
> > +#define DMA_TDM0_RX 34
> > +#define DMA_TDM0_TX 35
> > +#define DMA_TDM1_RX 36
> > +#define DMA_AUDSRC 37
> > +#define DMA_SPI_NAND 38
> > +#define DMA_SPI_NOR 39
> > +#define DMA_UART4_RX 40
> > +#define DMA_UART4_TX 41
> > +#define DMA_SPI_NOR1 42
> > +
> > +#define DMA_CPU_A53 0
> > +#define DMA_CPU_C906_0 1
> > +#define DMA_CPU_C906_1 2
> > +
> > +
> > +#endif // __DT_BINDINGS_DMA_CV1800_H__
> > --
> > 2.44.0
> >
^ permalink raw reply
* 回复: [PATCH v2 2/2] ASoC: cdns: Add drivers of Cadence Multi-Channel I2S Controller
From: Xingyu Wu @ 2024-03-26 2:04 UTC (permalink / raw)
To: Mark Brown, Pierre-Louis Bossart
Cc: Liam Girdwood, Claudiu Beznea, Jaroslav Kysela, Takashi Iwai,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
alsa-devel@alsa-project.org, linux-sound@vger.kernel.org
In-Reply-To: <aeac0262-1054-4bc9-b5e9-653785305162@sirena.org.uk>
>
> On Wed, Mar 20, 2024 at 10:00:24AM -0500, Pierre-Louis Bossart wrote:
>
> > > + for (i = 0; i < CDNS_I2S_FIFO_DEPTH; i++) {
> > > + if (format == SNDRV_PCM_FORMAT_S16_LE) {
> > > + data[0] = p16[tx_ptr][0];
> > > + data[1] = p16[tx_ptr][1];
> > > + } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
> > > + data[0] = p32[tx_ptr][0];
> > > + data[1] = p32[tx_ptr][1];
> > > + }
>
> > what about other formats implied by the use of 'else if' ?
>
> In general things like this should be written as switch statements.
OK, I will fix it in next version of this patch.
Thanks,
Xingyu Wu
^ permalink raw reply
* [PATCH v4 0/1] Add StarFive JH8100 dwmac support
From: Tan Chun Hau @ 2024-03-26 5:25 UTC (permalink / raw)
To: David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Rob Herring, Emil Renner Berthing, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Maxime Coquelin,
Alexandre Torgue, Simon Horman, Bartosz Golaszewski,
Andrew Halaney, Jisheng Zhang, Uwe Kleine-König,
Russell King
Cc: Ley Foon Tan, Jee Heng Sia, netdev, devicetree, linux-kernel,
linux-stm32, linux-arm-kernel, linux-riscv
Add StarFive JH8100 dwmac support.
The JH8100 dwmac shares the same driver code as the JH7110 dwmac
and has only one reset signal.
Please refer to below:
JH8100: reset-names = "stmmaceth";
JH7110: reset-names = "stmmaceth", "ahb";
JH7100: reset-names = "ahb";
Example usage of JH8100 in the device tree:
gmac0: ethernet@16030000 {
compatible = "starfive,jh8100-dwmac",
"starfive,jh7110-dwmac",
"snps,dwmac-5.20";
...
};
Changes in v4:
- restructure content based on feedback received.
Tan Chun Hau (1):
dt-bindings: net: starfive,jh7110-dwmac: Add StarFive JH8100 support
.../devicetree/bindings/net/snps,dwmac.yaml | 1 +
.../bindings/net/starfive,jh7110-dwmac.yaml | 54 ++++++++++++++-----
2 files changed, 41 insertions(+), 14 deletions(-)
--
2.25.1
^ permalink raw reply
* RE: [PATCH v2 6/6] misc: pci_endpoint_test: Add Device ID for R-Car V4H PCIe controller
From: Yoshihiro Shimoda @ 2024-03-26 5:47 UTC (permalink / raw)
To: Frank Li
Cc: lpieralisi@kernel.org, kw@linux.com, robh@kernel.org,
bhelgaas@google.com, krzysztof.kozlowski+dt@linaro.org,
conor+dt@kernel.org, jingoohan1@gmail.com,
gustavo.pimentel@synopsys.com, mani@kernel.org,
marek.vasut+renesas@gmail.com, linux-pci@vger.kernel.org,
devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
Geert Uytterhoeven
In-Reply-To: <ZgI/IGe2L0rJ8SSF@lizhi-Precision-Tower-5810>
Hi Frank,
> From: Frank Li, Sent: Tuesday, March 26, 2024 12:21 PM
> On Tue, Mar 26, 2024 at 11:45:40AM +0900, Yoshihiro Shimoda wrote:
> > Add Renesas R8A779G0 in pci_device_id table so that pci-epf-test
> > can be used for testing PCIe EP on R-Car V4H.
> >
> > Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
> > Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
> > ---
> > drivers/misc/pci_endpoint_test.c | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> > index c38a6083f0a7..2fa3c6473c7d 100644
> > --- a/drivers/misc/pci_endpoint_test.c
> > +++ b/drivers/misc/pci_endpoint_test.c
> > @@ -83,6 +83,7 @@
> > #define PCI_DEVICE_ID_RENESAS_R8A774C0 0x002d
> > #define PCI_DEVICE_ID_RENESAS_R8A774E1 0x0025
> > #define PCI_DEVICE_ID_RENESAS_R8A779F0 0x0031
> > +#define PCI_DEVICE_ID_RENESAS_R8A779G0 0x0030
> >
> > static DEFINE_IDA(pci_endpoint_test_ida);
> >
> > @@ -1005,6 +1006,9 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
> > { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779F0),
> > .driver_data = (kernel_ulong_t)&default_data,
> > },
> > + { PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A779G0),
> > + .driver_data = (kernel_ulong_t)&default_data,
> > + },
>
> You use default_data, why need new device_id? I think you can use 0x0031
> to do test.
I thought we can add a new device_id freely like other devices.
Since the PCIe controller's endpoint mode can configure the device id,
I can use 0x0031 to do test though.
If such a reusable entry exists, is adding a new device id into the driver prohibited?
Best regards,
Yoshihiro Shimoda
> Frank
>
> > { PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
> > .driver_data = (kernel_ulong_t)&j721e_data,
> > },
> > --
> > 2.25.1
> >
^ permalink raw reply
* Re: [PATCH v1 1/4] dt-bindings: input: Add Himax HX83102J touchscreen
From: Allen Lin @ 2024-03-26 5:46 UTC (permalink / raw)
To: Conor Dooley
Cc: Rob Herring, dmitry.torokhov, krzysztof.kozlowski+dt, conor+dt,
jikos, benjamin.tissoires, linux-input, devicetree, linux-kernel
In-Reply-To: <20240322-rectified-udder-fef9102f58da@spud>
Conor Dooley <conor@kernel.org> 於 2024年3月23日 週六 上午2:34寫道:
>
> On Fri, Mar 22, 2024 at 01:30:09PM -0500, Rob Herring wrote:
> > On Fri, Mar 22, 2024 at 05:54:08PM +0000, Conor Dooley wrote:
> > > On Fri, Mar 22, 2024 at 04:56:03PM +0800, Allen_Lin wrote:
> > > > Add the HX83102j touchscreen device tree bindings documents.
> > > > HX83102j is a Himax TDDI touchscreen controller.
> > > > It's power sequence should be bound with a lcm driver, thus it
> > > > needs to be a panel follower. Others are the same as normal SPI
> > > > touchscreen controller.
> > > >
> > > > Signed-off-by: Allen_Lin <allencl_lin@hotmail.com>
> > >
> > > note to self/Krzysztof/Rob:
> > > There was a previous attempt at this kind of device. This version looks
> > > better but might be incomplete given there's a bunch more properties in
> > > that patchset:
> > > https://lore.kernel.org/all/20231017091900.801989-1-tylor_yang@himax.corp-partner.google.com/
> >
> > Those don't look like properties we want coming back.
>
> Oh, I don't want most of them coming back either. There are some
> supplies in there though that I think we would like to come back, no?
> Maybe this particular device doesn't have any supplies, but that doesn't
> really seem credible.
We will use Firmware-name in Device Tree.
For power supply settings, because there may be other device using
same regulator.
We plan to define it as an optional property for user to control in
next release.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox