From 323af24998ec6dacd690722fae6018589c7f752c Mon Sep 17 00:00:00 2001 From: Nick Hollinghurst Date: Tue, 14 Feb 2023 14:58:33 +0000 Subject: [PATCH] drm: Add RP1 DSI driver Add support for the RP1 DSI hardware. Signed-off-by: Nick Hollinghurst drm/rp1: depends on, instead of select, MFD_RP1 According to kconfig-language.txt [1], select should be used only for "non-visible symbols ... and for symbols with no dependencies". Since MFD_RP1 both is visible and has a dependency, "select" should not be used and "depends on" should be used instead. In particular, this fixes the build of this kernel tree on NixOS, where its kernel config system will try to answer 'M' to as many config as possible. [1] https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html Signed-off-by: Ratchanan Srirattanamet --- drivers/gpu/drm/Kconfig | 2 + drivers/gpu/drm/Makefile | 1 + drivers/gpu/drm/rp1/Kconfig | 5 + drivers/gpu/drm/rp1/Makefile | 4 + drivers/gpu/drm/rp1/rp1-dsi/Kconfig | 14 + drivers/gpu/drm/rp1/rp1-dsi/Makefile | 5 + drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c | 534 ++++++++ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h | 94 ++ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c | 443 ++++++ drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c | 1503 +++++++++++++++++++++ 10 files changed, 2605 insertions(+) create mode 100644 drivers/gpu/drm/rp1/Kconfig create mode 100644 drivers/gpu/drm/rp1/Makefile create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Kconfig create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/Makefile create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c create mode 100644 drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 6b2c6b91f9625..af4079e7ec1af 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -392,6 +392,8 @@ source "drivers/gpu/drm/v3d/Kconfig" source "drivers/gpu/drm/vc4/Kconfig" +source "drivers/gpu/drm/rp1/Kconfig" + source "drivers/gpu/drm/loongson/Kconfig" source "drivers/gpu/drm/etnaviv/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index fa432a1ac9e2b..7e33cc221e2a0 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -218,3 +218,4 @@ obj-y += solomon/ obj-$(CONFIG_DRM_SPRD) += sprd/ obj-$(CONFIG_DRM_LOONGSON) += loongson/ obj-$(CONFIG_DRM_POWERVR) += imagination/ +obj-y += rp1/ diff --git a/drivers/gpu/drm/rp1/Kconfig b/drivers/gpu/drm/rp1/Kconfig new file mode 100644 index 0000000000000..d73c62e0ab64c --- /dev/null +++ b/drivers/gpu/drm/rp1/Kconfig @@ -0,0 +1,5 @@ +source "drivers/gpu/drm/rp1/rp1-dsi/Kconfig" + +source "drivers/gpu/drm/rp1/rp1-dpi/Kconfig" + +source "drivers/gpu/drm/rp1/rp1-vec/Kconfig" diff --git a/drivers/gpu/drm/rp1/Makefile b/drivers/gpu/drm/rp1/Makefile new file mode 100644 index 0000000000000..0f915b158e96f --- /dev/null +++ b/drivers/gpu/drm/rp1/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_DRM_RP1_DSI) += rp1-dsi/ +obj-$(CONFIG_DRM_RP1_DPI) += rp1-dpi/ +obj-$(CONFIG_DRM_RP1_VEC) += rp1-vec/ + diff --git a/drivers/gpu/drm/rp1/rp1-dsi/Kconfig b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig new file mode 100644 index 0000000000000..80c57bc487925 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +config DRM_RP1_DSI + tristate "DRM Support for RP1 DSI" + depends on DRM && MFD_RP1 + select DRM_GEM_DMA_HELPER + select DRM_KMS_HELPER + select DRM_MIPI_DSI + select DRM_VRAM_HELPER + select DRM_TTM + select DRM_TTM_HELPER + select GENERIC_PHY + select GENERIC_PHY_MIPI_DPHY + help + Choose this option to enable DSI display on RP1 diff --git a/drivers/gpu/drm/rp1/rp1-dsi/Makefile b/drivers/gpu/drm/rp1/rp1-dsi/Makefile new file mode 100644 index 0000000000000..1a9672c7bda02 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +drm-rp1-dsi-y := rp1_dsi.o rp1_dsi_dma.o rp1_dsi_dsi.o + +obj-$(CONFIG_DRM_RP1_DSI) += drm-rp1-dsi.o diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c new file mode 100644 index 0000000000000..0f5ef9bda8f54 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.c @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 + * + * Copyright (c) 2023 Raspberry Pi Limited. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rp1_dsi.h" + +static inline struct rp1_dsi * +bridge_to_rp1_dsi(struct drm_bridge *bridge) +{ + return container_of(bridge, struct rp1_dsi, bridge); +} + +static void rp1_dsi_bridge_pre_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ + struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); + + rp1dsi_dsi_setup(dsi, &dsi->pipe.crtc.state->adjusted_mode); +} + +static void rp1_dsi_bridge_enable(struct drm_bridge *bridge, + struct drm_bridge_state *old_state) +{ +} + +static void rp1_dsi_bridge_disable(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ +} + +static void rp1_dsi_bridge_post_disable(struct drm_bridge *bridge, + struct drm_bridge_state *state) +{ + struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); + + if (dsi->dsi_running) { + rp1dsi_dsi_stop(dsi); + dsi->dsi_running = false; + } +} + +static int rp1_dsi_bridge_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct rp1_dsi *dsi = bridge_to_rp1_dsi(bridge); + + /* Attach the panel or bridge to the dsi bridge */ + return drm_bridge_attach(bridge->encoder, dsi->out_bridge, + &dsi->bridge, flags); + return 0; +} + +static const struct drm_bridge_funcs rp1_dsi_bridge_funcs = { + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, + .atomic_reset = drm_atomic_helper_bridge_reset, + .atomic_pre_enable = rp1_dsi_bridge_pre_enable, + .atomic_enable = rp1_dsi_bridge_enable, + .atomic_disable = rp1_dsi_bridge_disable, + .atomic_post_disable = rp1_dsi_bridge_post_disable, + .attach = rp1_dsi_bridge_attach, +}; + +static void rp1dsi_pipe_update(struct drm_simple_display_pipe *pipe, + struct drm_plane_state *old_state) +{ + struct drm_pending_vblank_event *event; + unsigned long flags; + struct drm_framebuffer *fb = pipe->plane.state->fb; + struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; + struct drm_gem_object *gem = fb ? drm_gem_fb_get_obj(fb, 0) : NULL; + struct drm_gem_dma_object *dma_obj = gem ? to_drm_gem_dma_obj(gem) : NULL; + bool can_update = fb && dma_obj && dsi && dsi->pipe_enabled; + + /* (Re-)start DSI,DMA where required; and update FB address */ + if (can_update) { + if (!dsi->dma_running || fb->format->format != dsi->cur_fmt) { + if (dsi->dma_running && fb->format->format != dsi->cur_fmt) { + rp1dsi_dma_stop(dsi); + dsi->dma_running = false; + } + if (!dsi->dma_running) { + rp1dsi_dma_setup(dsi, + fb->format->format, dsi->display_format, + &pipe->crtc.state->adjusted_mode); + dsi->dma_running = true; + } + dsi->cur_fmt = fb->format->format; + drm_crtc_vblank_on(&pipe->crtc); + } + rp1dsi_dma_update(dsi, dma_obj->dma_addr, fb->offsets[0], fb->pitches[0]); + } + + /* Arm VBLANK event (or call it immediately in some error cases) */ + spin_lock_irqsave(&pipe->crtc.dev->event_lock, flags); + event = pipe->crtc.state->event; + if (event) { + pipe->crtc.state->event = NULL; + if (can_update && drm_crtc_vblank_get(&pipe->crtc) == 0) + drm_crtc_arm_vblank_event(&pipe->crtc, event); + else + drm_crtc_send_vblank_event(&pipe->crtc, event); + } + spin_unlock_irqrestore(&pipe->crtc.dev->event_lock, flags); +} + +static inline struct rp1_dsi * +encoder_to_rp1_dsi(struct drm_encoder *encoder) +{ + struct drm_simple_display_pipe *pipe = + container_of(encoder, struct drm_simple_display_pipe, encoder); + return container_of(pipe, struct rp1_dsi, pipe); +} + +static void rp1dsi_encoder_enable(struct drm_encoder *encoder) +{ + struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); + + /* Put DSI into video mode before starting video */ + rp1dsi_dsi_set_cmdmode(dsi, 0); + + /* Start DMA -> DPI */ + dsi->pipe_enabled = true; + dsi->cur_fmt = 0xdeadbeef; + rp1dsi_pipe_update(&dsi->pipe, 0); +} + +static void rp1dsi_encoder_disable(struct drm_encoder *encoder) +{ + struct rp1_dsi *dsi = encoder_to_rp1_dsi(encoder); + + drm_crtc_vblank_off(&dsi->pipe.crtc); + if (dsi->dma_running) { + rp1dsi_dma_stop(dsi); + dsi->dma_running = false; + } + dsi->pipe_enabled = false; + + /* Return to command mode after stopping video */ + rp1dsi_dsi_set_cmdmode(dsi, 1); +} + +static const struct drm_encoder_helper_funcs rp1_dsi_encoder_funcs = { + .enable = rp1dsi_encoder_enable, + .disable = rp1dsi_encoder_disable, +}; + +static void rp1dsi_pipe_enable(struct drm_simple_display_pipe *pipe, + struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ +} + +static void rp1dsi_pipe_disable(struct drm_simple_display_pipe *pipe) +{ +} + +static int rp1dsi_pipe_enable_vblank(struct drm_simple_display_pipe *pipe) +{ + struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; + + if (dsi) + rp1dsi_dma_vblank_ctrl(dsi, 1); + + return 0; +} + +static void rp1dsi_pipe_disable_vblank(struct drm_simple_display_pipe *pipe) +{ + struct rp1_dsi *dsi = pipe->crtc.dev->dev_private; + + if (dsi) + rp1dsi_dma_vblank_ctrl(dsi, 0); +} + +static const struct drm_simple_display_pipe_funcs rp1dsi_pipe_funcs = { + .enable = rp1dsi_pipe_enable, + .update = rp1dsi_pipe_update, + .disable = rp1dsi_pipe_disable, + .enable_vblank = rp1dsi_pipe_enable_vblank, + .disable_vblank = rp1dsi_pipe_disable_vblank, +}; + +static const struct drm_mode_config_funcs rp1dsi_mode_funcs = { + .fb_create = drm_gem_fb_create, + .atomic_check = drm_atomic_helper_check, + .atomic_commit = drm_atomic_helper_commit, +}; + +static const u32 rp1dsi_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_RGB565 +}; + +static void rp1dsi_stopall(struct drm_device *drm) +{ + if (drm->dev_private) { + struct rp1_dsi *dsi = drm->dev_private; + + if (dsi->dma_running || rp1dsi_dma_busy(dsi)) { + rp1dsi_dma_stop(dsi); + dsi->dma_running = false; + } + if (dsi->dsi_running) { + rp1dsi_dsi_stop(dsi); + dsi->dsi_running = false; + } + if (dsi->clocks[RP1DSI_CLOCK_CFG]) + clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_CFG]); + } +} + +DEFINE_DRM_GEM_DMA_FOPS(rp1dsi_fops); + +static struct drm_driver rp1dsi_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC, + .fops = &rp1dsi_fops, + .name = "drm-rp1-dsi", + .desc = "drm-rp1-dsi", + .date = "0", + .major = 1, + .minor = 0, + DRM_GEM_DMA_DRIVER_OPS, + .release = rp1dsi_stopall, +}; + +static int rp1dsi_bind(struct rp1_dsi *dsi) +{ + struct platform_device *pdev = dsi->pdev; + struct drm_device *drm = dsi->drm; + int ret; + + dsi->out_bridge = drmm_of_get_bridge(drm, pdev->dev.of_node, 0, 0); + if (IS_ERR(dsi->out_bridge)) + return PTR_ERR(dsi->out_bridge); + + ret = drmm_mode_config_init(drm); + if (ret) + goto rtn; + + drm->mode_config.max_width = 4096; + drm->mode_config.max_height = 4096; + drm->mode_config.preferred_depth = 32; + drm->mode_config.prefer_shadow = 0; + drm->mode_config.quirk_addfb_prefer_host_byte_order = true; + drm->mode_config.funcs = &rp1dsi_mode_funcs; + drm_vblank_init(drm, 1); + + ret = drm_simple_display_pipe_init(drm, + &dsi->pipe, + &rp1dsi_pipe_funcs, + rp1dsi_formats, + ARRAY_SIZE(rp1dsi_formats), + NULL, NULL); + if (ret) + goto rtn; + + /* We need slightly more complex encoder handling (enabling/disabling + * video mode), so add encoder helper functions. + */ + drm_encoder_helper_add(&dsi->pipe.encoder, &rp1_dsi_encoder_funcs); + + ret = drm_simple_display_pipe_attach_bridge(&dsi->pipe, &dsi->bridge); + if (ret) + goto rtn; + + drm_bridge_add(&dsi->bridge); + + drm_mode_config_reset(drm); + + if (dsi->clocks[RP1DSI_CLOCK_CFG]) + clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_CFG]); + + ret = drm_dev_register(drm, 0); + + if (ret == 0) + drm_fbdev_ttm_setup(drm, 32); + +rtn: + if (ret) + dev_err(&pdev->dev, "%s returned %d\n", __func__, ret); + else + dev_info(&pdev->dev, "%s succeeded", __func__); + + return ret; +} + +static void rp1dsi_unbind(struct rp1_dsi *dsi) +{ + struct drm_device *drm = dsi->drm; + + rp1dsi_stopall(drm); + drm_dev_unregister(drm); + drm_atomic_helper_shutdown(drm); +} + +static int rp1dsi_host_attach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) +{ + struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); + + dev_info(&dsi->pdev->dev, "%s: Attach DSI device name=%s channel=%d lanes=%d format=%d flags=0x%lx hs_rate=%lu lp_rate=%lu", + __func__, dsi_dev->name, dsi_dev->channel, dsi_dev->lanes, + dsi_dev->format, dsi_dev->mode_flags, dsi_dev->hs_rate, + dsi_dev->lp_rate); + dsi->vc = dsi_dev->channel & 3; + dsi->lanes = dsi_dev->lanes; + + switch (dsi_dev->format) { + case MIPI_DSI_FMT_RGB666: + case MIPI_DSI_FMT_RGB666_PACKED: + case MIPI_DSI_FMT_RGB565: + case MIPI_DSI_FMT_RGB888: + break; + default: + return -EINVAL; + } + dsi->display_format = dsi_dev->format; + dsi->display_flags = dsi_dev->mode_flags; + dsi->display_hs_rate = dsi_dev->hs_rate; + dsi->display_lp_rate = dsi_dev->lp_rate; + + /* + * Previously, we added a separate component to handle panel/bridge + * discovery and DRM registration, but now it's just a function call. + * The downstream/attaching device should deal with -EPROBE_DEFER + */ + return rp1dsi_bind(dsi); +} + +static int rp1dsi_host_detach(struct mipi_dsi_host *host, struct mipi_dsi_device *dsi_dev) +{ + struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); + + /* + * Unregister the DRM driver. + * TODO: Check we are cleaning up correctly and not doing things multiple times! + */ + rp1dsi_unbind(dsi); + return 0; +} + +static ssize_t rp1dsi_host_transfer(struct mipi_dsi_host *host, const struct mipi_dsi_msg *msg) +{ + struct rp1_dsi *dsi = container_of(host, struct rp1_dsi, dsi_host); + struct mipi_dsi_packet packet; + int ret = 0; + + /* Write */ + ret = mipi_dsi_create_packet(&packet, msg); + if (ret) { + dev_err(dsi->drm->dev, "RP1DSI: failed to create packet: %d\n", ret); + return ret; + } + + rp1dsi_dsi_send(dsi, *(u32 *)(&packet.header), packet.payload_length, packet.payload); + + /* Optional read back */ + if (msg->rx_len && msg->rx_buf) + ret = rp1dsi_dsi_recv(dsi, msg->rx_len, msg->rx_buf); + + return (ssize_t)ret; +} + +static const struct mipi_dsi_host_ops rp1dsi_mipi_dsi_host_ops = { + .attach = rp1dsi_host_attach, + .detach = rp1dsi_host_detach, + .transfer = rp1dsi_host_transfer +}; + +static int rp1dsi_platform_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct drm_device *drm; + struct rp1_dsi *dsi; + int i, ret; + + drm = drm_dev_alloc(&rp1dsi_driver, dev); + if (IS_ERR(drm)) { + ret = PTR_ERR(drm); + return ret; + } + dsi = drmm_kzalloc(drm, sizeof(*dsi), GFP_KERNEL); + if (!dsi) { + ret = -ENOMEM; + goto err_free_drm; + } + init_completion(&dsi->finished); + dsi->drm = drm; + dsi->pdev = pdev; + drm->dev_private = dsi; + platform_set_drvdata(pdev, drm); + + dsi->bridge.funcs = &rp1_dsi_bridge_funcs; + dsi->bridge.of_node = dev->of_node; + dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; + + /* Safe default values for DSI mode */ + dsi->lanes = 1; + dsi->display_format = MIPI_DSI_FMT_RGB888; + dsi->display_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; + + /* Hardware resources */ + for (i = 0; i < RP1DSI_NUM_CLOCKS; i++) { + static const char * const myclocknames[RP1DSI_NUM_CLOCKS] = { + "cfgclk", "dpiclk", "byteclk", "refclk" + }; + dsi->clocks[i] = devm_clk_get(dev, myclocknames[i]); + if (IS_ERR(dsi->clocks[i])) { + ret = PTR_ERR(dsi->clocks[i]); + dev_err(dev, "Error getting clocks[%d]\n", i); + goto err_free_drm; + } + } + + for (i = 0; i < RP1DSI_NUM_HW_BLOCKS; i++) { + dsi->hw_base[i] = + devm_ioremap_resource(dev, + platform_get_resource(dsi->pdev, + IORESOURCE_MEM, + i)); + if (IS_ERR(dsi->hw_base[i])) { + ret = PTR_ERR(dsi->hw_base[i]); + dev_err(dev, "Error memory mapping regs[%d]\n", i); + goto err_free_drm; + } + } + ret = platform_get_irq(dsi->pdev, 0); + if (ret > 0) + ret = devm_request_irq(dev, ret, rp1dsi_dma_isr, + IRQF_SHARED, "rp1-dsi", dsi); + if (ret) { + dev_err(dev, "Unable to request interrupt\n"); + ret = -EINVAL; + goto err_free_drm; + } + rp1dsi_mipicfg_setup(dsi); + dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); + + /* Create the MIPI DSI Host and wait for the panel/bridge to attach to it */ + dsi->dsi_host.ops = &rp1dsi_mipi_dsi_host_ops; + dsi->dsi_host.dev = dev; + ret = mipi_dsi_host_register(&dsi->dsi_host); + if (ret) + goto err_free_drm; + + return ret; + +err_free_drm: + dev_err(dev, "%s fail %d\n", __func__, ret); + drm_dev_put(drm); + return ret; +} + +static void rp1dsi_platform_remove(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + struct rp1_dsi *dsi = drm->dev_private; + + mipi_dsi_host_unregister(&dsi->dsi_host); +} + +static void rp1dsi_platform_shutdown(struct platform_device *pdev) +{ + struct drm_device *drm = platform_get_drvdata(pdev); + + rp1dsi_stopall(drm); +} + +static const struct of_device_id rp1dsi_of_match[] = { + { + .compatible = "raspberrypi,rp1dsi", + }, + { /* sentinel */ }, +}; + +MODULE_DEVICE_TABLE(of, rp1dsi_of_match); + +static struct platform_driver rp1dsi_platform_driver = { + .probe = rp1dsi_platform_probe, + .remove = rp1dsi_platform_remove, + .shutdown = rp1dsi_platform_shutdown, + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = rp1dsi_of_match, + }, +}; + +module_platform_driver(rp1dsi_platform_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("MIPI DSI driver for Raspberry Pi RP1"); +MODULE_AUTHOR("Nick Hollinghurst"); diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h new file mode 100644 index 0000000000000..c40186748a3f7 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi.h @@ -0,0 +1,94 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * DRM Driver for DSI output on Raspberry Pi RP1 + * + * Copyright (c) 2023 Raspberry Pi Limited. + */ +#ifndef _RP1_DSI_H_ +#define _RP1_DSI_H_ + +#include +#include +#include + +#include +#include +#include +#include + +#define MODULE_NAME "drm-rp1-dsi" +#define DRIVER_NAME "drm-rp1-dsi" + +/* ---------------------------------------------------------------------- */ + +#define RP1DSI_HW_BLOCK_DMA 0 +#define RP1DSI_HW_BLOCK_DSI 1 +#define RP1DSI_HW_BLOCK_CFG 2 +#define RP1DSI_NUM_HW_BLOCKS 3 + +#define RP1DSI_CLOCK_CFG 0 +#define RP1DSI_CLOCK_DPI 1 +#define RP1DSI_CLOCK_BYTE 2 +#define RP1DSI_CLOCK_REF 3 +#define RP1DSI_NUM_CLOCKS 4 + +/* ---------------------------------------------------------------------- */ + +struct rp1_dsi { + /* DRM and platform device pointers */ + struct drm_device *drm; + struct platform_device *pdev; + + /* Framework and helper objects */ + struct drm_simple_display_pipe pipe; + struct drm_bridge bridge; + struct drm_bridge *out_bridge; + struct mipi_dsi_host dsi_host; + + /* Clocks. We need DPI clock; the others are frequency references */ + struct clk *clocks[RP1DSI_NUM_CLOCKS]; + + /* Block (DSI DMA, DSI Host) base addresses, and current state */ + void __iomem *hw_base[RP1DSI_NUM_HW_BLOCKS]; + u32 cur_fmt; + bool dsi_running, dma_running, pipe_enabled; + struct completion finished; + + /* Attached display parameters (from mipi_dsi_device) */ + unsigned long display_flags, display_hs_rate, display_lp_rate; + enum mipi_dsi_pixel_format display_format; + u8 vc; + u8 lanes; + + /* DPHY */ + u8 hsfreq_index; +}; + +/* ---------------------------------------------------------------------- */ +/* Functions to control the DSI/DPI/DMA block */ + +void rp1dsi_dma_setup(struct rp1_dsi *dsi, + u32 in_format, enum mipi_dsi_pixel_format out_format, + struct drm_display_mode const *mode); +void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride); +void rp1dsi_dma_stop(struct rp1_dsi *dsi); +int rp1dsi_dma_busy(struct rp1_dsi *dsi); +irqreturn_t rp1dsi_dma_isr(int irq, void *dev); +void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable); + +/* ---------------------------------------------------------------------- */ +/* Functions to control the MIPICFG block and check RP1 platform */ + +void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi); + +/* ---------------------------------------------------------------------- */ +/* Functions to control the SNPS D-PHY and DSI block setup */ + +void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode); +void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 header, int len, const u8 *buf); +int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf); +void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int cmd_mode); +void rp1dsi_dsi_stop(struct rp1_dsi *dsi); + +#endif + diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c new file mode 100644 index 0000000000000..85bb0615bae99 --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dma.c @@ -0,0 +1,443 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 + * + * Copyright (c) 2023 Raspberry Pi Limited. + */ + +#include +#include + +#include +#include +#include + +#include "rp1_dsi.h" + +// --- DPI DMA REGISTERS (derived from Argon firmware, via RP1 drivers/mipi, with corrections) --- + +// Control +#define DPI_DMA_CONTROL 0x0 +#define DPI_DMA_CONTROL_ARM_SHIFT 0 +#define DPI_DMA_CONTROL_ARM_MASK BIT(DPI_DMA_CONTROL_ARM_SHIFT) +#define DPI_DMA_CONTROL_ALIGN16_SHIFT 2 +#define DPI_DMA_CONTROL_ALIGN16_MASK BIT(DPI_DMA_CONTROL_ALIGN16_SHIFT) +#define DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT 1 +#define DPI_DMA_CONTROL_AUTO_REPEAT_MASK BIT(DPI_DMA_CONTROL_AUTO_REPEAT_SHIFT) +#define DPI_DMA_CONTROL_HIGH_WATER_SHIFT 3 +#define DPI_DMA_CONTROL_HIGH_WATER_MASK (0x1FF << DPI_DMA_CONTROL_HIGH_WATER_SHIFT) +#define DPI_DMA_CONTROL_DEN_POL_SHIFT 12 +#define DPI_DMA_CONTROL_DEN_POL_MASK BIT(DPI_DMA_CONTROL_DEN_POL_SHIFT) +#define DPI_DMA_CONTROL_HSYNC_POL_SHIFT 13 +#define DPI_DMA_CONTROL_HSYNC_POL_MASK BIT(DPI_DMA_CONTROL_HSYNC_POL_SHIFT) +#define DPI_DMA_CONTROL_VSYNC_POL_SHIFT 14 +#define DPI_DMA_CONTROL_VSYNC_POL_MASK BIT(DPI_DMA_CONTROL_VSYNC_POL_SHIFT) +#define DPI_DMA_CONTROL_COLORM_SHIFT 15 +#define DPI_DMA_CONTROL_COLORM_MASK BIT(DPI_DMA_CONTROL_COLORM_SHIFT) +#define DPI_DMA_CONTROL_SHUTDN_SHIFT 16 +#define DPI_DMA_CONTROL_SHUTDN_MASK BIT(DPI_DMA_CONTROL_SHUTDN_SHIFT) +#define DPI_DMA_CONTROL_HBP_EN_SHIFT 17 +#define DPI_DMA_CONTROL_HBP_EN_MASK BIT(DPI_DMA_CONTROL_HBP_EN_SHIFT) +#define DPI_DMA_CONTROL_HFP_EN_SHIFT 18 +#define DPI_DMA_CONTROL_HFP_EN_MASK BIT(DPI_DMA_CONTROL_HFP_EN_SHIFT) +#define DPI_DMA_CONTROL_VBP_EN_SHIFT 19 +#define DPI_DMA_CONTROL_VBP_EN_MASK BIT(DPI_DMA_CONTROL_VBP_EN_SHIFT) +#define DPI_DMA_CONTROL_VFP_EN_SHIFT 20 +#define DPI_DMA_CONTROL_VFP_EN_MASK BIT(DPI_DMA_CONTROL_VFP_EN_SHIFT) +#define DPI_DMA_CONTROL_HSYNC_EN_SHIFT 21 +#define DPI_DMA_CONTROL_HSYNC_EN_MASK BIT(DPI_DMA_CONTROL_HSYNC_EN_SHIFT) +#define DPI_DMA_CONTROL_VSYNC_EN_SHIFT 22 +#define DPI_DMA_CONTROL_VSYNC_EN_MASK BIT(DPI_DMA_CONTROL_VSYNC_EN_SHIFT) +#define DPI_DMA_CONTROL_FORCE_IMMED_SHIFT 23 +#define DPI_DMA_CONTROL_FORCE_IMMED_MASK BIT(DPI_DMA_CONTROL_FORCE_IMMED_SHIFT) +#define DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT 24 +#define DPI_DMA_CONTROL_FORCE_DRAIN_MASK BIT(DPI_DMA_CONTROL_FORCE_DRAIN_SHIFT) +#define DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT 25 +#define DPI_DMA_CONTROL_FORCE_EMPTY_MASK BIT(DPI_DMA_CONTROL_FORCE_EMPTY_SHIFT) + +// IRQ_ENABLES +#define DPI_DMA_IRQ_EN 0x04 +#define DPI_DMA_IRQ_EN_DMA_READY_SHIFT 0 +#define DPI_DMA_IRQ_EN_DMA_READY_MASK BIT(DPI_DMA_IRQ_EN_DMA_READY_SHIFT) +#define DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT 1 +#define DPI_DMA_IRQ_EN_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_EN_UNDERFLOW_SHIFT) +#define DPI_DMA_IRQ_EN_FRAME_START_SHIFT 2 +#define DPI_DMA_IRQ_EN_FRAME_START_MASK BIT(DPI_DMA_IRQ_EN_FRAME_START_SHIFT) +#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT 3 +#define DPI_DMA_IRQ_EN_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_EN_AFIFO_EMPTY_SHIFT) +#define DPI_DMA_IRQ_EN_TE_SHIFT 4 +#define DPI_DMA_IRQ_EN_TE_MASK BIT(DPI_DMA_IRQ_EN_TE_SHIFT) +#define DPI_DMA_IRQ_EN_ERROR_SHIFT 5 +#define DPI_DMA_IRQ_EN_ERROR_MASK BIT(DPI_DMA_IRQ_EN_ERROR_SHIFT) +#define DPI_DMA_IRQ_EN_MATCH_SHIFT 6 +#define DPI_DMA_IRQ_EN_MATCH_MASK BIT(DPI_DMA_IRQ_EN_MATCH_SHIFT) +#define DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT 16 +#define DPI_DMA_IRQ_EN_MATCH_LINE_MASK (0xFFF << DPI_DMA_IRQ_EN_MATCH_LINE_SHIFT) + +// IRQ_FLAGS +#define DPI_DMA_IRQ_FLAGS 0x08 +#define DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT 0 +#define DPI_DMA_IRQ_FLAGS_DMA_READY_MASK BIT(DPI_DMA_IRQ_FLAGS_DMA_READY_SHIFT) +#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT 1 +#define DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK BIT(DPI_DMA_IRQ_FLAGS_UNDERFLOW_SHIFT) +#define DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT 2 +#define DPI_DMA_IRQ_FLAGS_FRAME_START_MASK BIT(DPI_DMA_IRQ_FLAGS_FRAME_START_SHIFT) +#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT 3 +#define DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK BIT(DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_SHIFT) +#define DPI_DMA_IRQ_FLAGS_TE_SHIFT 4 +#define DPI_DMA_IRQ_FLAGS_TE_MASK BIT(DPI_DMA_IRQ_FLAGS_TE_SHIFT) +#define DPI_DMA_IRQ_FLAGS_ERROR_SHIFT 5 +#define DPI_DMA_IRQ_FLAGS_ERROR_MASK BIT(DPI_DMA_IRQ_FLAGS_ERROR_SHIFT) +#define DPI_DMA_IRQ_FLAGS_MATCH_SHIFT 6 +#define DPI_DMA_IRQ_FLAGS_MATCH_MASK BIT(DPI_DMA_IRQ_FLAGS_MATCH_SHIFT) + +// QOS +#define DPI_DMA_QOS 0xC +#define DPI_DMA_QOS_DQOS_SHIFT 0 +#define DPI_DMA_QOS_DQOS_MASK (0xF << DPI_DMA_QOS_DQOS_SHIFT) +#define DPI_DMA_QOS_ULEV_SHIFT 4 +#define DPI_DMA_QOS_ULEV_MASK (0xF << DPI_DMA_QOS_ULEV_SHIFT) +#define DPI_DMA_QOS_UQOS_SHIFT 8 +#define DPI_DMA_QOS_UQOS_MASK (0xF << DPI_DMA_QOS_UQOS_SHIFT) +#define DPI_DMA_QOS_LLEV_SHIFT 12 +#define DPI_DMA_QOS_LLEV_MASK (0xF << DPI_DMA_QOS_LLEV_SHIFT) +#define DPI_DMA_QOS_LQOS_SHIFT 16 +#define DPI_DMA_QOS_LQOS_MASK (0xF << DPI_DMA_QOS_LQOS_SHIFT) + +// Panics +#define DPI_DMA_PANICS 0x38 +#define DPI_DMA_PANICS_UPPER_COUNT_SHIFT 0 +#define DPI_DMA_PANICS_UPPER_COUNT_MASK \ + (0x0000FFFF << DPI_DMA_PANICS_UPPER_COUNT_SHIFT) +#define DPI_DMA_PANICS_LOWER_COUNT_SHIFT 16 +#define DPI_DMA_PANICS_LOWER_COUNT_MASK \ + (0x0000FFFF << DPI_DMA_PANICS_LOWER_COUNT_SHIFT) + +// DMA Address Lower: +#define DPI_DMA_DMA_ADDR_L 0x10 + +// DMA Address Upper: +#define DPI_DMA_DMA_ADDR_H 0x40 + +// DMA stride +#define DPI_DMA_DMA_STRIDE 0x14 + +// Visible Area +#define DPI_DMA_VISIBLE_AREA 0x18 +#define DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT 0 +#define DPI_DMA_VISIBLE_AREA_ROWSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_ROWSM1_SHIFT) +#define DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT 16 +#define DPI_DMA_VISIBLE_AREA_COLSM1_MASK (0x0FFF << DPI_DMA_VISIBLE_AREA_COLSM1_SHIFT) + +// Sync width +#define DPI_DMA_SYNC_WIDTH 0x1C +#define DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT 0 +#define DPI_DMA_SYNC_WIDTH_ROWSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_ROWSM1_SHIFT) +#define DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT 16 +#define DPI_DMA_SYNC_WIDTH_COLSM1_MASK (0x0FFF << DPI_DMA_SYNC_WIDTH_COLSM1_SHIFT) + +// Back porch +#define DPI_DMA_BACK_PORCH 0x20 +#define DPI_DMA_BACK_PORCH_ROWSM1_SHIFT 0 +#define DPI_DMA_BACK_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_ROWSM1_SHIFT) +#define DPI_DMA_BACK_PORCH_COLSM1_SHIFT 16 +#define DPI_DMA_BACK_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_BACK_PORCH_COLSM1_SHIFT) + +// Front porch +#define DPI_DMA_FRONT_PORCH 0x24 +#define DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT 0 +#define DPI_DMA_FRONT_PORCH_ROWSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_ROWSM1_SHIFT) +#define DPI_DMA_FRONT_PORCH_COLSM1_SHIFT 16 +#define DPI_DMA_FRONT_PORCH_COLSM1_MASK (0x0FFF << DPI_DMA_FRONT_PORCH_COLSM1_SHIFT) + +// Input masks +#define DPI_DMA_IMASK 0x2C +#define DPI_DMA_IMASK_R_SHIFT 0 +#define DPI_DMA_IMASK_R_MASK (0x3FF << DPI_DMA_IMASK_R_SHIFT) +#define DPI_DMA_IMASK_G_SHIFT 10 +#define DPI_DMA_IMASK_G_MASK (0x3FF << DPI_DMA_IMASK_G_SHIFT) +#define DPI_DMA_IMASK_B_SHIFT 20 +#define DPI_DMA_IMASK_B_MASK (0x3FF << DPI_DMA_IMASK_B_SHIFT) + +// Output Masks +#define DPI_DMA_OMASK 0x30 +#define DPI_DMA_OMASK_R_SHIFT 0 +#define DPI_DMA_OMASK_R_MASK (0x3FF << DPI_DMA_OMASK_R_SHIFT) +#define DPI_DMA_OMASK_G_SHIFT 10 +#define DPI_DMA_OMASK_G_MASK (0x3FF << DPI_DMA_OMASK_G_SHIFT) +#define DPI_DMA_OMASK_B_SHIFT 20 +#define DPI_DMA_OMASK_B_MASK (0x3FF << DPI_DMA_OMASK_B_SHIFT) + +// Shifts +#define DPI_DMA_SHIFT 0x28 +#define DPI_DMA_SHIFT_IR_SHIFT 0 +#define DPI_DMA_SHIFT_IR_MASK (0x1F << DPI_DMA_SHIFT_IR_SHIFT) +#define DPI_DMA_SHIFT_IG_SHIFT 5 +#define DPI_DMA_SHIFT_IG_MASK (0x1F << DPI_DMA_SHIFT_IG_SHIFT) +#define DPI_DMA_SHIFT_IB_SHIFT 10 +#define DPI_DMA_SHIFT_IB_MASK (0x1F << DPI_DMA_SHIFT_IB_SHIFT) +#define DPI_DMA_SHIFT_OR_SHIFT 15 +#define DPI_DMA_SHIFT_OR_MASK (0x1F << DPI_DMA_SHIFT_OR_SHIFT) +#define DPI_DMA_SHIFT_OG_SHIFT 20 +#define DPI_DMA_SHIFT_OG_MASK (0x1F << DPI_DMA_SHIFT_OG_SHIFT) +#define DPI_DMA_SHIFT_OB_SHIFT 25 +#define DPI_DMA_SHIFT_OB_MASK (0x1F << DPI_DMA_SHIFT_OB_SHIFT) + +// Scaling +#define DPI_DMA_RGBSZ 0x34 +#define DPI_DMA_RGBSZ_BPP_SHIFT 16 +#define DPI_DMA_RGBSZ_BPP_MASK (0x3 << DPI_DMA_RGBSZ_BPP_SHIFT) +#define DPI_DMA_RGBSZ_R_SHIFT 0 +#define DPI_DMA_RGBSZ_R_MASK (0xF << DPI_DMA_RGBSZ_R_SHIFT) +#define DPI_DMA_RGBSZ_G_SHIFT 4 +#define DPI_DMA_RGBSZ_G_MASK (0xF << DPI_DMA_RGBSZ_G_SHIFT) +#define DPI_DMA_RGBSZ_B_SHIFT 8 +#define DPI_DMA_RGBSZ_B_MASK (0xF << DPI_DMA_RGBSZ_B_SHIFT) + +// Status +#define DPI_DMA_STATUS 0x3c + +#define BITS(field, val) (((val) << (field ## _SHIFT)) & (field ## _MASK)) + +static unsigned int rp1dsi_dma_read(struct rp1_dsi *dsi, unsigned int reg) +{ + void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg; + + return readl(addr); +} + +static void rp1dsi_dma_write(struct rp1_dsi *dsi, unsigned int reg, unsigned int val) +{ + void __iomem *addr = dsi->hw_base[RP1DSI_HW_BLOCK_DMA] + reg; + + writel(val, addr); +} + +int rp1dsi_dma_busy(struct rp1_dsi *dsi) +{ + return (rp1dsi_dma_read(dsi, DPI_DMA_STATUS) & 0xF8F) ? 1 : 0; +} + +/* Table of supported input (in-memory/DMA) pixel formats. */ +struct rp1dsi_ipixfmt { + u32 format; /* DRM format code */ + u32 mask; /* RGB masks (10 bits each, left justified) */ + u32 shift; /* RGB MSB positions in the memory word */ + u32 rgbsz; /* Shifts used for scaling; also (BPP/8-1) */ +}; + +#define IMASK_RGB(r, g, b) (BITS(DPI_DMA_IMASK_R, r) | \ + BITS(DPI_DMA_IMASK_G, g) | \ + BITS(DPI_DMA_IMASK_B, b)) +#define ISHIFT_RGB(r, g, b) (BITS(DPI_DMA_SHIFT_IR, r) | \ + BITS(DPI_DMA_SHIFT_IG, g) | \ + BITS(DPI_DMA_SHIFT_IB, b)) + +static const struct rp1dsi_ipixfmt my_formats[] = { + { + .format = DRM_FORMAT_XRGB8888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { + .format = DRM_FORMAT_XBGR8888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(7, 15, 23), + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 3), + }, + { + .format = DRM_FORMAT_RGB888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(23, 15, 7), + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), + }, + { + .format = DRM_FORMAT_BGR888, + .mask = IMASK_RGB(0x3fc, 0x3fc, 0x3fc), + .shift = ISHIFT_RGB(7, 15, 23), + .rgbsz = BITS(DPI_DMA_RGBSZ_BPP, 2), + }, + { + .format = DRM_FORMAT_RGB565, + .mask = IMASK_RGB(0x3e0, 0x3f0, 0x3e0), + .shift = ISHIFT_RGB(15, 10, 4), + .rgbsz = BITS(DPI_DMA_RGBSZ_R, 5) | BITS(DPI_DMA_RGBSZ_G, 6) | + BITS(DPI_DMA_RGBSZ_B, 5) | BITS(DPI_DMA_RGBSZ_BPP, 1), + } +}; + +/* Choose the internal on-the-bus DPI format as expected by DSI Host. */ +static u32 get_omask_oshift(enum mipi_dsi_pixel_format fmt, u32 *oshift) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB565: + *oshift = BITS(DPI_DMA_SHIFT_OR, 15) | + BITS(DPI_DMA_SHIFT_OG, 10) | + BITS(DPI_DMA_SHIFT_OB, 4); + return BITS(DPI_DMA_OMASK_R, 0x3e0) | + BITS(DPI_DMA_OMASK_G, 0x3f0) | + BITS(DPI_DMA_OMASK_B, 0x3e0); + case MIPI_DSI_FMT_RGB666_PACKED: + *oshift = BITS(DPI_DMA_SHIFT_OR, 17) | + BITS(DPI_DMA_SHIFT_OG, 11) | + BITS(DPI_DMA_SHIFT_OB, 5); + return BITS(DPI_DMA_OMASK_R, 0x3f0) | + BITS(DPI_DMA_OMASK_G, 0x3f0) | + BITS(DPI_DMA_OMASK_B, 0x3f0); + case MIPI_DSI_FMT_RGB666: + *oshift = BITS(DPI_DMA_SHIFT_OR, 21) | + BITS(DPI_DMA_SHIFT_OG, 13) | + BITS(DPI_DMA_SHIFT_OB, 5); + return BITS(DPI_DMA_OMASK_R, 0x3f0) | + BITS(DPI_DMA_OMASK_G, 0x3f0) | + BITS(DPI_DMA_OMASK_B, 0x3f0); + default: + *oshift = BITS(DPI_DMA_SHIFT_OR, 23) | + BITS(DPI_DMA_SHIFT_OG, 15) | + BITS(DPI_DMA_SHIFT_OB, 7); + return BITS(DPI_DMA_OMASK_R, 0x3fc) | + BITS(DPI_DMA_OMASK_G, 0x3fc) | + BITS(DPI_DMA_OMASK_B, 0x3fc); + } +} + +void rp1dsi_dma_setup(struct rp1_dsi *dsi, + u32 in_format, enum mipi_dsi_pixel_format out_format, + struct drm_display_mode const *mode) +{ + u32 oshift; + int i; + + /* + * Configure all DSI/DPI/DMA block registers, except base address. + * DMA will not actually start until a FB base address is specified + * using rp1dsi_dma_update(). + */ + + rp1dsi_dma_write(dsi, DPI_DMA_VISIBLE_AREA, + BITS(DPI_DMA_VISIBLE_AREA_ROWSM1, mode->vdisplay - 1) | + BITS(DPI_DMA_VISIBLE_AREA_COLSM1, mode->hdisplay - 1)); + + rp1dsi_dma_write(dsi, DPI_DMA_SYNC_WIDTH, + BITS(DPI_DMA_SYNC_WIDTH_ROWSM1, mode->vsync_end - mode->vsync_start - 1) | + BITS(DPI_DMA_SYNC_WIDTH_COLSM1, mode->hsync_end - mode->hsync_start - 1)); + + /* In the DPIDMA registers, "back porch" time includes sync width */ + rp1dsi_dma_write(dsi, DPI_DMA_BACK_PORCH, + BITS(DPI_DMA_BACK_PORCH_ROWSM1, mode->vtotal - mode->vsync_start - 1) | + BITS(DPI_DMA_BACK_PORCH_COLSM1, mode->htotal - mode->hsync_start - 1)); + + rp1dsi_dma_write(dsi, DPI_DMA_FRONT_PORCH, + BITS(DPI_DMA_FRONT_PORCH_ROWSM1, mode->vsync_start - mode->vdisplay - 1) | + BITS(DPI_DMA_FRONT_PORCH_COLSM1, mode->hsync_start - mode->hdisplay - 1)); + + /* Input to output pixel format conversion */ + for (i = 0; i < ARRAY_SIZE(my_formats); ++i) { + if (my_formats[i].format == in_format) + break; + } + if (i >= ARRAY_SIZE(my_formats)) { + drm_err(dsi->drm, "%s: bad input format\n", __func__); + i = 0; + } + rp1dsi_dma_write(dsi, DPI_DMA_IMASK, my_formats[i].mask); + rp1dsi_dma_write(dsi, DPI_DMA_OMASK, get_omask_oshift(out_format, &oshift)); + rp1dsi_dma_write(dsi, DPI_DMA_SHIFT, my_formats[i].shift | oshift); + if (out_format == MIPI_DSI_FMT_RGB888) + rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz); + else + rp1dsi_dma_write(dsi, DPI_DMA_RGBSZ, my_formats[i].rgbsz & DPI_DMA_RGBSZ_BPP_MASK); + + rp1dsi_dma_write(dsi, DPI_DMA_QOS, + BITS(DPI_DMA_QOS_DQOS, 0x0) | + BITS(DPI_DMA_QOS_ULEV, 0xb) | + BITS(DPI_DMA_QOS_UQOS, 0x2) | + BITS(DPI_DMA_QOS_LLEV, 0x8) | + BITS(DPI_DMA_QOS_LQOS, 0x7)); + + rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, -1); + rp1dsi_dma_vblank_ctrl(dsi, 1); + + i = rp1dsi_dma_busy(dsi); + if (i) + drm_err(dsi->drm, "RP1DSI: Unexpectedly busy at start!"); + + rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, + BITS(DPI_DMA_CONTROL_ARM, (i == 0)) | + BITS(DPI_DMA_CONTROL_AUTO_REPEAT, 1) | + BITS(DPI_DMA_CONTROL_HIGH_WATER, 448) | + BITS(DPI_DMA_CONTROL_DEN_POL, 0) | + BITS(DPI_DMA_CONTROL_HSYNC_POL, 0) | + BITS(DPI_DMA_CONTROL_VSYNC_POL, 0) | + BITS(DPI_DMA_CONTROL_COLORM, 0) | + BITS(DPI_DMA_CONTROL_SHUTDN, 0) | + BITS(DPI_DMA_CONTROL_HBP_EN, 1) | + BITS(DPI_DMA_CONTROL_HFP_EN, 1) | + BITS(DPI_DMA_CONTROL_VBP_EN, 1) | + BITS(DPI_DMA_CONTROL_VFP_EN, 1) | + BITS(DPI_DMA_CONTROL_HSYNC_EN, 1) | + BITS(DPI_DMA_CONTROL_VSYNC_EN, 1)); +} + +void rp1dsi_dma_update(struct rp1_dsi *dsi, dma_addr_t addr, u32 offset, u32 stride) +{ + /* + * Update STRIDE, DMAH and DMAL only. When called after rp1dsi_dma_setup(), + * DMA starts immediately; if already running, the buffer will flip at + * the next vertical sync event. + */ + u64 a = addr + offset; + + rp1dsi_dma_write(dsi, DPI_DMA_DMA_STRIDE, stride); + rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_H, a >> 32); + rp1dsi_dma_write(dsi, DPI_DMA_DMA_ADDR_L, a & 0xFFFFFFFFu); +} + +void rp1dsi_dma_stop(struct rp1_dsi *dsi) +{ + /* + * Stop DMA by turning off the Auto-Repeat flag, and wait up to 100ms for + * the current and any queued frame to end. "Force drain" flags are not used, + * as they seem to prevent DMA from re-starting properly; it's safer to wait. + */ + u32 ctrl; + + reinit_completion(&dsi->finished); + ctrl = rp1dsi_dma_read(dsi, DPI_DMA_CONTROL); + ctrl &= ~(DPI_DMA_CONTROL_ARM_MASK | DPI_DMA_CONTROL_AUTO_REPEAT_MASK); + rp1dsi_dma_write(dsi, DPI_DMA_CONTROL, ctrl); + if (!wait_for_completion_timeout(&dsi->finished, HZ / 10)) + drm_err(dsi->drm, "%s: timed out waiting for idle\n", __func__); + rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, 0); +} + +void rp1dsi_dma_vblank_ctrl(struct rp1_dsi *dsi, int enable) +{ + rp1dsi_dma_write(dsi, DPI_DMA_IRQ_EN, + BITS(DPI_DMA_IRQ_EN_AFIFO_EMPTY, 1) | + BITS(DPI_DMA_IRQ_EN_UNDERFLOW, 1) | + BITS(DPI_DMA_IRQ_EN_DMA_READY, !!enable) | + BITS(DPI_DMA_IRQ_EN_MATCH_LINE, 4095)); +} + +irqreturn_t rp1dsi_dma_isr(int irq, void *dev) +{ + struct rp1_dsi *dsi = dev; + u32 u = rp1dsi_dma_read(dsi, DPI_DMA_IRQ_FLAGS); + + if (u) { + rp1dsi_dma_write(dsi, DPI_DMA_IRQ_FLAGS, u); + if (dsi) { + if (u & DPI_DMA_IRQ_FLAGS_UNDERFLOW_MASK) + drm_err_ratelimited(dsi->drm, + "Underflow! (panics=0x%08x)\n", + rp1dsi_dma_read(dsi, DPI_DMA_PANICS)); + if (u & DPI_DMA_IRQ_FLAGS_DMA_READY_MASK) + drm_crtc_handle_vblank(&dsi->pipe.crtc); + if (u & DPI_DMA_IRQ_FLAGS_AFIFO_EMPTY_MASK) + complete(&dsi->finished); + } + } + return u ? IRQ_HANDLED : IRQ_NONE; +} diff --git a/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c new file mode 100644 index 0000000000000..63b167da9895e --- /dev/null +++ b/drivers/gpu/drm/rp1/rp1-dsi/rp1_dsi_dsi.c @@ -0,0 +1,1503 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * DRM Driver for DSI output on Raspberry Pi RP1 + * + * Copyright (c) 2023 Raspberry Pi Limited. + */ + +#include +#include +#include +#include +#include "drm/drm_print.h" + +#include "rp1_dsi.h" + +/* ------------------------------- Synopsis DSI ------------------------ */ +#define DSI_VERSION_CFG 0x000 +#define DSI_PWR_UP 0x004 +#define DSI_CLKMGR_CFG 0x008 +#define DSI_DPI_VCID 0x00C +#define DSI_DPI_COLOR_CODING 0x010 +#define DSI_DPI_CFG_POL 0x014 +#define DSI_DPI_LP_CMD_TIM 0x018 +#define DSI_DBI_VCID 0x01C +#define DSI_DBI_CFG 0x020 +#define DSI_DBI_PARTITIONING_EN 0x024 +#define DSI_DBI_CMDSIZE 0x028 +#define DSI_PCKHDL_CFG 0x02C +#define DSI_GEN_VCID 0x030 +#define DSI_MODE_CFG 0x034 +#define DSI_VID_MODE_CFG 0x038 +#define DSI_VID_PKT_SIZE 0x03C +#define DSI_VID_NUM_CHUNKS 0x040 +#define DSI_VID_NULL_SIZE 0x044 +#define DSI_VID_HSA_TIME 0x048 +#define DSI_VID_HBP_TIME 0x04C +#define DSI_VID_HLINE_TIME 0x050 +#define DSI_VID_VSA_LINES 0x054 +#define DSI_VID_VBP_LINES 0x058 +#define DSI_VID_VFP_LINES 0x05C +#define DSI_VID_VACTIVE_LINES 0x060 +#define DSI_EDPI_CMD_SIZE 0x064 +#define DSI_CMD_MODE_CFG 0x068 +#define DSI_GEN_HDR 0x06C +#define DSI_GEN_PLD_DATA 0x070 +#define DSI_CMD_PKT_STATUS 0x074 +#define DSI_TO_CNT_CFG 0x078 +#define DSI_HS_RD_TO_CNT 0x07C +#define DSI_LP_RD_TO_CNT 0x080 +#define DSI_HS_WR_TO_CNT 0x084 +#define DSI_LP_WR_TO_CNT 0x088 +#define DSI_BTA_TO_CNT 0x08C +#define DSI_SDF_3D 0x090 +#define DSI_LPCLK_CTRL 0x094 +#define DSI_PHY_TMR_LPCLK_CFG 0x098 +#define DSI_PHY_TMR_HS2LP_LSB 16 +#define DSI_PHY_TMR_LP2HS_LSB 0 +#define DSI_PHY_TMR_CFG 0x09C +#define DSI_PHY_TMR_RD_CFG 0x0F4 +#define DSI_PHYRSTZ 0x0A0 +#define DSI_PHY_IF_CFG 0x0A4 +#define DSI_PHY_ULPS_CTRL 0x0A8 +#define DSI_PHY_TX_TRIGGERS 0x0AC +#define DSI_PHY_STATUS 0x0B0 + +#define DSI_PHY_TST_CTRL0 0x0B4 +#define DSI_PHY_TST_CTRL1 0x0B8 +#define DSI_INT_ST0 0x0BC +#define DSI_INT_ST1 0x0C0 +#define DSI_INT_MASK0_CFG 0x0C4 +#define DSI_INT_MASK1_CFG 0x0C8 +#define DSI_PHY_CAL 0x0CC +#define DSI_HEXP_NPKT_CLR 0x104 +#define DSI_HEXP_NPKT_SIZE 0x108 +#define DSI_VID_SHADOW_CTRL 0x100 + +#define DSI_DPI_VCID_ACT 0x10C +#define DSI_DPI_COLOR_CODING_ACT 0x110 +#define DSI_DPI_LP_CMD_TIM_ACT 0x118 +#define DSI_VID_MODE_CFG_ACT 0x138 +#define DSI_VID_PKT_SIZE_ACT 0x13C +#define DSI_VID_NUM_CHUNKS_ACT 0x140 +#define DSI_VID_NULL_SIZE_ACT 0x144 +#define DSI_VID_HSA_TIME_ACT 0x148 +#define DSI_VID_HBP_TIME_ACT 0x14C +#define DSI_VID_HLINE_TIME_ACT 0x150 +#define DSI_VID_VSA_LINES_ACT 0x154 +#define DSI_VID_VBP_LINES_ACT 0x158 +#define DSI_VID_VFP_LINES_ACT 0x15C +#define DSI_VID_VACTIVE_LINES_ACT 0x160 +#define DSI_SDF_3D_CFG_ACT 0x190 + +#define DSI_INT_FORCE0 0x0D8 +#define DSI_INT_FORCE1 0x0DC + +#define DSI_AUTO_ULPS_MODE 0x0E0 +#define DSI_AUTO_ULPS_ENTRY_DELAY 0x0E4 +#define DSI_AUTO_ULPS_WAKEUP_TIME 0x0E8 +#define DSI_EDPI_ADV_FEATURES 0x0EC + +#define DSI_DSC_PARAMETER 0x0F0 + +/* And some bitfield definitions */ + +#define DPHY_PWR_UP_SHUTDOWNZ_LSB 0 +#define DPHY_PWR_UP_SHUTDOWNZ_BITS BIT(DPHY_PWR_UP_SHUTDOWNZ_LSB) + +#define DPHY_CTRL0_PHY_TESTCLK_LSB 1 +#define DPHY_CTRL0_PHY_TESTCLK_BITS BIT(DPHY_CTRL0_PHY_TESTCLK_LSB) +#define DPHY_CTRL0_PHY_TESTCLR_LSB 0 +#define DPHY_CTRL0_PHY_TESTCLR_BITS BIT(DPHY_CTRL0_PHY_TESTCLR_LSB) + +#define DPHY_CTRL1_PHY_TESTDIN_LSB 0 +#define DPHY_CTRL1_PHY_TESTDIN_BITS (0xff << DPHY_CTRL1_PHY_TESTDIN_LSB) +#define DPHY_CTRL1_PHY_TESTDOUT_LSB 8 +#define DPHY_CTRL1_PHY_TESTDOUT_BITS (0xff << DPHY_CTRL1_PHY_TESTDOUT_LSB) +#define DPHY_CTRL1_PHY_TESTEN_LSB 16 +#define DPHY_CTRL1_PHY_TESTEN_BITS BIT(DPHY_CTRL1_PHY_TESTEN_LSB) + +#define DSI_PHYRSTZ_SHUTDOWNZ_LSB 0 +#define DSI_PHYRSTZ_SHUTDOWNZ_BITS BIT(DSI_PHYRSTZ_SHUTDOWNZ_LSB) +#define DSI_PHYRSTZ_RSTZ_LSB 1 +#define DSI_PHYRSTZ_RSTZ_BITS BIT(DSI_PHYRSTZ_RSTZ_LSB) +#define DSI_PHYRSTZ_ENABLECLK_LSB 2 +#define DSI_PHYRSTZ_ENABLECLK_BITS BIT(DSI_PHYRSTZ_ENABLECLK_LSB) +#define DSI_PHYRSTZ_FORCEPLL_LSB 3 +#define DSI_PHYRSTZ_FORCEPLL_BITS BIT(DSI_PHYRSTZ_FORCEPLL_LSB) + +#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44 +#define DPHY_PLL_INPUT_DIV_OFFSET 0x17 +#define DPHY_PLL_LOOP_DIV_OFFSET 0x18 +#define DPHY_PLL_DIV_CTRL_OFFSET 0x19 + +#define DPHY_PLL_BIAS_OFFSET 0x10 +#define DPHY_PLL_BIAS_VCO_RANGE_LSB 3 +#define DPHY_PLL_BIAS_USE_PROGRAMMED_VCO_RANGE BIT(7) + +#define DPHY_PLL_CHARGE_PUMP_OFFSET 0x11 +#define DPHY_PLL_LPF_OFFSET 0x12 + +#define DSI_WRITE(reg, val) writel((val), dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg)) +#define DSI_READ(reg) readl(dsi->hw_base[RP1DSI_HW_BLOCK_DSI] + (reg)) + +// ================================================================================ +// Register block : RPI_MIPICFG +// Version : 1 +// Bus type : apb +// Description : Register block to control mipi DPHY +// ================================================================================ +#define RPI_MIPICFG_REGS_RWTYPE_MSB 13 +#define RPI_MIPICFG_REGS_RWTYPE_LSB 12 +// ================================================================================ +// Register : RPI_MIPICFG_CLK2FC +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_CLK2FC_OFFSET 0x00000000 +#define RPI_MIPICFG_CLK2FC_BITS 0x00000007 +#define RPI_MIPICFG_CLK2FC_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_CLK2FC_SEL +// Description : select a clock to be sent to the frequency counter +// 7 = none +// 6 = none +// 5 = none +// 4 = rxbyteclkhs (187.5MHz) +// 3 = rxclkesc0 (20MHz) +// 2 = txbyteclkhs (187.5MHz) +// 1 = txclkesc (125MHz) +// 0 = none +#define RPI_MIPICFG_CLK2FC_SEL_RESET 0x0 +#define RPI_MIPICFG_CLK2FC_SEL_BITS 0x00000007 +#define RPI_MIPICFG_CLK2FC_SEL_MSB 2 +#define RPI_MIPICFG_CLK2FC_SEL_LSB 0 +#define RPI_MIPICFG_CLK2FC_SEL_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_CFG +// JTAG access : asynchronous +// Description : Top level configuration +#define RPI_MIPICFG_CFG_OFFSET 0x00000004 +#define RPI_MIPICFG_CFG_BITS 0x00000111 +#define RPI_MIPICFG_CFG_RESET 0x00000001 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_CFG_DPIUPDATE +// Description : Indicate the DSI block that the next frame will have a new video configuration +#define RPI_MIPICFG_CFG_DPIUPDATE_RESET 0x0 +#define RPI_MIPICFG_CFG_DPIUPDATE_BITS 0x00000100 +#define RPI_MIPICFG_CFG_DPIUPDATE_MSB 8 +#define RPI_MIPICFG_CFG_DPIUPDATE_LSB 8 +#define RPI_MIPICFG_CFG_DPIUPDATE_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_CFG_SEL_TE_EXT +// Description : Select the TE source: 1 - ext, 0 - int +#define RPI_MIPICFG_CFG_SEL_TE_EXT_RESET 0x0 +#define RPI_MIPICFG_CFG_SEL_TE_EXT_BITS 0x00000010 +#define RPI_MIPICFG_CFG_SEL_TE_EXT_MSB 4 +#define RPI_MIPICFG_CFG_SEL_TE_EXT_LSB 4 +#define RPI_MIPICFG_CFG_SEL_TE_EXT_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_CFG_SEL_CSI_DSI_N +// Description : Select PHY direction: input to CSI, output from DSI. CSI 1 DSI 0 +#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_RESET 0x1 +#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_BITS 0x00000001 +#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_MSB 0 +#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_LSB 0 +#define RPI_MIPICFG_CFG_SEL_CSI_DSI_N_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_TE +// JTAG access : synchronous +// Description : Tearing effect processing +#define RPI_MIPICFG_TE_OFFSET 0x00000008 +#define RPI_MIPICFG_TE_BITS 0x10ffffff +#define RPI_MIPICFG_TE_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_TE_ARM +// Description : Tearing effect arm +#define RPI_MIPICFG_TE_ARM_RESET 0x0 +#define RPI_MIPICFG_TE_ARM_BITS 0x10000000 +#define RPI_MIPICFG_TE_ARM_MSB 28 +#define RPI_MIPICFG_TE_ARM_LSB 28 +#define RPI_MIPICFG_TE_ARM_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_TE_HALT_CYC +// Description : When arm pulse has been seen, wait for te; then halt the dpi block +// for this many clk_dpi cycles +#define RPI_MIPICFG_TE_HALT_CYC_RESET 0x000000 +#define RPI_MIPICFG_TE_HALT_CYC_BITS 0x00ffffff +#define RPI_MIPICFG_TE_HALT_CYC_MSB 23 +#define RPI_MIPICFG_TE_HALT_CYC_LSB 0 +#define RPI_MIPICFG_TE_HALT_CYC_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_MONITOR +// JTAG access : asynchronous +// Description : DPHY status monitors for analog DFT +#define RPI_MIPICFG_DPHY_MONITOR_OFFSET 0x00000010 +#define RPI_MIPICFG_DPHY_MONITOR_BITS 0x00111fff +#define RPI_MIPICFG_DPHY_MONITOR_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_MONITOR_LOCK +// Description : None +#define RPI_MIPICFG_DPHY_MONITOR_LOCK_RESET 0x0 +#define RPI_MIPICFG_DPHY_MONITOR_LOCK_BITS 0x00100000 +#define RPI_MIPICFG_DPHY_MONITOR_LOCK_MSB 20 +#define RPI_MIPICFG_DPHY_MONITOR_LOCK_LSB 20 +#define RPI_MIPICFG_DPHY_MONITOR_LOCK_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_MONITOR_BISTOK +// Description : None +#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_RESET 0x0 +#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_BITS 0x00010000 +#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_MSB 16 +#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_LSB 16 +#define RPI_MIPICFG_DPHY_MONITOR_BISTOK_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK +// Description : None +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_RESET 0x0 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_BITS 0x00001000 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_MSB 12 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_LSB 12 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATECLK_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA +// Description : None +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_RESET 0x0 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_BITS 0x00000f00 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_MSB 11 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_LSB 8 +#define RPI_MIPICFG_DPHY_MONITOR_STOPSTATEDATA_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_MONITOR_TESTDOUT +// Description : None +#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_RESET 0x00 +#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_BITS 0x000000ff +#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_MSB 7 +#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_LSB 0 +#define RPI_MIPICFG_DPHY_MONITOR_TESTDOUT_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_CTRL_0 +// JTAG access : asynchronous +// Description : DPHY control for analog DFT +#define RPI_MIPICFG_DPHY_CTRL_0_OFFSET 0x00000014 +#define RPI_MIPICFG_DPHY_CTRL_0_BITS 0x0000003f +#define RPI_MIPICFG_DPHY_CTRL_0_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE +// Description : When set in lpmode, TXCLKESC is driven from clk_vec(driven from clocks block) +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_BITS 0x00000020 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_MSB 5 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_LSB 5 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_LPMODE_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA +// Description : When set, drive the DPHY from the test registers +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_BITS 0x00000010 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_MSB 4 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_LSB 4 +#define RPI_MIPICFG_DPHY_CTRL_0_TEST_ENA_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS +// Description : When test_ena is set, disable cfg_clk +#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_BITS 0x00000008 +#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_MSB 3 +#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_LSB 3 +#define RPI_MIPICFG_DPHY_CTRL_0_CFG_CLK_DIS_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS +// Description : When test_ena is set, disable refclk +#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_BITS 0x00000004 +#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_MSB 2 +#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_LSB 2 +#define RPI_MIPICFG_DPHY_CTRL_0_REFCLK_DIS_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS +// Description : When test_ena is set, disable txclkesc +#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_BITS 0x00000002 +#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_MSB 1 +#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_LSB 1 +#define RPI_MIPICFG_DPHY_CTRL_0_TXCLKESC_DIS_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS +// Description : When test_ena is set, disable txbyteclkhs +#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_BITS 0x00000001 +#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_MSB 0 +#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_LSB 0 +#define RPI_MIPICFG_DPHY_CTRL_0_TXBYTECLKHS_DIS_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_CTRL_1 +// JTAG access : asynchronous +// Description : DPHY control for analog DFT +#define RPI_MIPICFG_DPHY_CTRL_1_OFFSET 0x00000018 +#define RPI_MIPICFG_DPHY_CTRL_1_BITS 0x7fffffff +#define RPI_MIPICFG_DPHY_CTRL_1_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_BITS 0x40000000 +#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_MSB 30 +#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_LSB 30 +#define RPI_MIPICFG_DPHY_CTRL_1_FORCEPLL_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_BITS 0x20000000 +#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_MSB 29 +#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_LSB 29 +#define RPI_MIPICFG_DPHY_CTRL_1_SHUTDOWNZ_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_RSTZ +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_BITS 0x10000000 +#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_MSB 28 +#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_LSB 28 +#define RPI_MIPICFG_DPHY_CTRL_1_RSTZ_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_BITS 0x08000000 +#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_MSB 27 +#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_LSB 27 +#define RPI_MIPICFG_DPHY_CTRL_1_MASTERSLAVEZ_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_BISTON +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_BITS 0x04000000 +#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_MSB 26 +#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_LSB 26 +#define RPI_MIPICFG_DPHY_CTRL_1_BISTON_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_BITS 0x02000000 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_MSB 25 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_LSB 25 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTHSCLK_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_BITS 0x01000000 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_MSB 24 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_LSB 24 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLECLK_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_BITS 0x00800000 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_MSB 23 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_LSB 23 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_BITS 0x00400000 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_MSB 22 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_LSB 22 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_BITS 0x00200000 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_MSB 21 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_LSB 21 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_BITS 0x00100000 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_MSB 20 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_LSB 20 +#define RPI_MIPICFG_DPHY_CTRL_1_ENABLE_0_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_BITS 0x00080000 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_MSB 19 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_LSB 19 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_BITS 0x00040000 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_MSB 18 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_LSB 18 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_BITS 0x00020000 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_MSB 17 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_LSB 17 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_BITS 0x00010000 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_MSB 16 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_LSB 16 +#define RPI_MIPICFG_DPHY_CTRL_1_BASEDIR_0_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_BITS 0x00008000 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_MSB 15 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_LSB 15 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_BITS 0x00004000 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_MSB 14 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_LSB 14 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_BITS 0x00002000 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_MSB 13 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_LSB 13 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_BITS 0x00001000 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_MSB 12 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_LSB 12 +#define RPI_MIPICFG_DPHY_CTRL_1_TXLPDTESC_0_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_BITS 0x00000800 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_MSB 11 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_LSB 11 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_BITS 0x00000400 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_MSB 10 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_LSB 10 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_BITS 0x00000200 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_MSB 9 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_LSB 9 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_BITS 0x00000100 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_MSB 8 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_LSB 8 +#define RPI_MIPICFG_DPHY_CTRL_1_TXVALIDESC_0_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_BITS 0x00000080 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_MSB 7 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_LSB 7 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_BITS 0x00000040 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_MSB 6 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_LSB 6 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_BITS 0x00000020 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_MSB 5 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_LSB 5 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_BITS 0x00000010 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_MSB 4 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_LSB 4 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTESC_0_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_BITS 0x00000008 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_MSB 3 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_LSB 3 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_BITS 0x00000004 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_MSB 2 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_LSB 2 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_BITS 0x00000002 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_MSB 1 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_LSB 1 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_BITS 0x00000001 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_MSB 0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_LSB 0 +#define RPI_MIPICFG_DPHY_CTRL_1_TXREQUESTDATAHS_0_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_CTRL_2 +// JTAG access : asynchronous +// Description : DPHY control for analog DFT +#define RPI_MIPICFG_DPHY_CTRL_2_OFFSET 0x0000001c +#define RPI_MIPICFG_DPHY_CTRL_2_BITS 0x000007ff +#define RPI_MIPICFG_DPHY_CTRL_2_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLK +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_BITS 0x00000400 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_MSB 10 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_LSB 10 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLK_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTEN +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_BITS 0x00000200 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_MSB 9 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_LSB 9 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTEN_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTCLR +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_RESET 0x0 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_BITS 0x00000100 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_MSB 8 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_LSB 8 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTCLR_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_2_TESTDIN +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_BITS 0x000000ff +#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_MSB 7 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_LSB 0 +#define RPI_MIPICFG_DPHY_CTRL_2_TESTDIN_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_CTRL_3 +// JTAG access : asynchronous +// Description : DPHY control for analog DFT +#define RPI_MIPICFG_DPHY_CTRL_3_OFFSET 0x00000020 +#define RPI_MIPICFG_DPHY_CTRL_3_BITS 0xffffffff +#define RPI_MIPICFG_DPHY_CTRL_3_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_BITS 0xff000000 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_MSB 31 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_LSB 24 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_BITS 0x00ff0000 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_MSB 23 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_LSB 16 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_BITS 0x0000ff00 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_MSB 15 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_LSB 8 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_BITS 0x000000ff +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_MSB 7 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_LSB 0 +#define RPI_MIPICFG_DPHY_CTRL_3_TXDATAESC_0_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_DPHY_CTRL_4 +// JTAG access : asynchronous +// Description : DPHY control for analog DFT +#define RPI_MIPICFG_DPHY_CTRL_4_OFFSET 0x00000024 +#define RPI_MIPICFG_DPHY_CTRL_4_BITS 0xffffffff +#define RPI_MIPICFG_DPHY_CTRL_4_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_BITS 0xff000000 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_MSB 31 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_LSB 24 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_3_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_BITS 0x00ff0000 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_MSB 23 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_LSB 16 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_2_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_BITS 0x0000ff00 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_MSB 15 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_LSB 8 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_1_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0 +// Description : None +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_RESET 0x00 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_BITS 0x000000ff +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_MSB 7 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_LSB 0 +#define RPI_MIPICFG_DPHY_CTRL_4_TXDATAHS_0_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_INTR +// JTAG access : synchronous +// Description : Raw Interrupts +#define RPI_MIPICFG_INTR_OFFSET 0x00000028 +#define RPI_MIPICFG_INTR_BITS 0x0000000f +#define RPI_MIPICFG_INTR_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTR_DSI_HOST +// Description : None +#define RPI_MIPICFG_INTR_DSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTR_DSI_HOST_BITS 0x00000008 +#define RPI_MIPICFG_INTR_DSI_HOST_MSB 3 +#define RPI_MIPICFG_INTR_DSI_HOST_LSB 3 +#define RPI_MIPICFG_INTR_DSI_HOST_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTR_CSI_HOST +// Description : None +#define RPI_MIPICFG_INTR_CSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTR_CSI_HOST_BITS 0x00000004 +#define RPI_MIPICFG_INTR_CSI_HOST_MSB 2 +#define RPI_MIPICFG_INTR_CSI_HOST_LSB 2 +#define RPI_MIPICFG_INTR_CSI_HOST_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTR_DSI_DMA +// Description : None +#define RPI_MIPICFG_INTR_DSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTR_DSI_DMA_BITS 0x00000002 +#define RPI_MIPICFG_INTR_DSI_DMA_MSB 1 +#define RPI_MIPICFG_INTR_DSI_DMA_LSB 1 +#define RPI_MIPICFG_INTR_DSI_DMA_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTR_CSI_DMA +// Description : None +#define RPI_MIPICFG_INTR_CSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTR_CSI_DMA_BITS 0x00000001 +#define RPI_MIPICFG_INTR_CSI_DMA_MSB 0 +#define RPI_MIPICFG_INTR_CSI_DMA_LSB 0 +#define RPI_MIPICFG_INTR_CSI_DMA_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_INTE +// JTAG access : synchronous +// Description : Interrupt Enable +#define RPI_MIPICFG_INTE_OFFSET 0x0000002c +#define RPI_MIPICFG_INTE_BITS 0x0000000f +#define RPI_MIPICFG_INTE_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTE_DSI_HOST +// Description : None +#define RPI_MIPICFG_INTE_DSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTE_DSI_HOST_BITS 0x00000008 +#define RPI_MIPICFG_INTE_DSI_HOST_MSB 3 +#define RPI_MIPICFG_INTE_DSI_HOST_LSB 3 +#define RPI_MIPICFG_INTE_DSI_HOST_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTE_CSI_HOST +// Description : None +#define RPI_MIPICFG_INTE_CSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTE_CSI_HOST_BITS 0x00000004 +#define RPI_MIPICFG_INTE_CSI_HOST_MSB 2 +#define RPI_MIPICFG_INTE_CSI_HOST_LSB 2 +#define RPI_MIPICFG_INTE_CSI_HOST_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTE_DSI_DMA +// Description : None +#define RPI_MIPICFG_INTE_DSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTE_DSI_DMA_BITS 0x00000002 +#define RPI_MIPICFG_INTE_DSI_DMA_MSB 1 +#define RPI_MIPICFG_INTE_DSI_DMA_LSB 1 +#define RPI_MIPICFG_INTE_DSI_DMA_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTE_CSI_DMA +// Description : None +#define RPI_MIPICFG_INTE_CSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTE_CSI_DMA_BITS 0x00000001 +#define RPI_MIPICFG_INTE_CSI_DMA_MSB 0 +#define RPI_MIPICFG_INTE_CSI_DMA_LSB 0 +#define RPI_MIPICFG_INTE_CSI_DMA_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_INTF +// JTAG access : synchronous +// Description : Interrupt Force +#define RPI_MIPICFG_INTF_OFFSET 0x00000030 +#define RPI_MIPICFG_INTF_BITS 0x0000000f +#define RPI_MIPICFG_INTF_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTF_DSI_HOST +// Description : None +#define RPI_MIPICFG_INTF_DSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTF_DSI_HOST_BITS 0x00000008 +#define RPI_MIPICFG_INTF_DSI_HOST_MSB 3 +#define RPI_MIPICFG_INTF_DSI_HOST_LSB 3 +#define RPI_MIPICFG_INTF_DSI_HOST_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTF_CSI_HOST +// Description : None +#define RPI_MIPICFG_INTF_CSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTF_CSI_HOST_BITS 0x00000004 +#define RPI_MIPICFG_INTF_CSI_HOST_MSB 2 +#define RPI_MIPICFG_INTF_CSI_HOST_LSB 2 +#define RPI_MIPICFG_INTF_CSI_HOST_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTF_DSI_DMA +// Description : None +#define RPI_MIPICFG_INTF_DSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTF_DSI_DMA_BITS 0x00000002 +#define RPI_MIPICFG_INTF_DSI_DMA_MSB 1 +#define RPI_MIPICFG_INTF_DSI_DMA_LSB 1 +#define RPI_MIPICFG_INTF_DSI_DMA_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTF_CSI_DMA +// Description : None +#define RPI_MIPICFG_INTF_CSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTF_CSI_DMA_BITS 0x00000001 +#define RPI_MIPICFG_INTF_CSI_DMA_MSB 0 +#define RPI_MIPICFG_INTF_CSI_DMA_LSB 0 +#define RPI_MIPICFG_INTF_CSI_DMA_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_INTS +// JTAG access : synchronous +// Description : Interrupt status after masking & forcing +#define RPI_MIPICFG_INTS_OFFSET 0x00000034 +#define RPI_MIPICFG_INTS_BITS 0x0000000f +#define RPI_MIPICFG_INTS_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTS_DSI_HOST +// Description : None +#define RPI_MIPICFG_INTS_DSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTS_DSI_HOST_BITS 0x00000008 +#define RPI_MIPICFG_INTS_DSI_HOST_MSB 3 +#define RPI_MIPICFG_INTS_DSI_HOST_LSB 3 +#define RPI_MIPICFG_INTS_DSI_HOST_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTS_CSI_HOST +// Description : None +#define RPI_MIPICFG_INTS_CSI_HOST_RESET 0x0 +#define RPI_MIPICFG_INTS_CSI_HOST_BITS 0x00000004 +#define RPI_MIPICFG_INTS_CSI_HOST_MSB 2 +#define RPI_MIPICFG_INTS_CSI_HOST_LSB 2 +#define RPI_MIPICFG_INTS_CSI_HOST_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTS_DSI_DMA +// Description : None +#define RPI_MIPICFG_INTS_DSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTS_DSI_DMA_BITS 0x00000002 +#define RPI_MIPICFG_INTS_DSI_DMA_MSB 1 +#define RPI_MIPICFG_INTS_DSI_DMA_LSB 1 +#define RPI_MIPICFG_INTS_DSI_DMA_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_INTS_CSI_DMA +// Description : None +#define RPI_MIPICFG_INTS_CSI_DMA_RESET 0x0 +#define RPI_MIPICFG_INTS_CSI_DMA_BITS 0x00000001 +#define RPI_MIPICFG_INTS_CSI_DMA_MSB 0 +#define RPI_MIPICFG_INTS_CSI_DMA_LSB 0 +#define RPI_MIPICFG_INTS_CSI_DMA_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_BLOCK_ID +// JTAG access : asynchronous +// Description : Block Identifier +#define RPI_MIPICFG_BLOCK_ID_OFFSET 0x00000038 +#define RPI_MIPICFG_BLOCK_ID_BITS 0xffffffff +#define RPI_MIPICFG_BLOCK_ID_RESET 0x4d495049 +#define RPI_MIPICFG_BLOCK_ID_MSB 31 +#define RPI_MIPICFG_BLOCK_ID_LSB 0 +#define RPI_MIPICFG_BLOCK_ID_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_INSTANCE_ID +// JTAG access : asynchronous +// Description : Block Instance Identifier +#define RPI_MIPICFG_INSTANCE_ID_OFFSET 0x0000003c +#define RPI_MIPICFG_INSTANCE_ID_BITS 0x0000000f +#define RPI_MIPICFG_INSTANCE_ID_RESET 0x00000000 +#define RPI_MIPICFG_INSTANCE_ID_MSB 3 +#define RPI_MIPICFG_INSTANCE_ID_LSB 0 +#define RPI_MIPICFG_INSTANCE_ID_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_RSTSEQ_AUTO +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_RSTSEQ_AUTO_OFFSET 0x00000040 +#define RPI_MIPICFG_RSTSEQ_AUTO_BITS 0x00000007 +#define RPI_MIPICFG_RSTSEQ_AUTO_RESET 0x00000007 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_AUTO_CSI +// Description : 1 = reset is controlled by the sequencer +// 0 = reset is controlled by rstseq_ctrl +#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_RESET 0x1 +#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_BITS 0x00000004 +#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_MSB 2 +#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_LSB 2 +#define RPI_MIPICFG_RSTSEQ_AUTO_CSI_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_AUTO_DPI +// Description : 1 = reset is controlled by the sequencer +// 0 = reset is controlled by rstseq_ctrl +#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_RESET 0x1 +#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_BITS 0x00000002 +#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_MSB 1 +#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_LSB 1 +#define RPI_MIPICFG_RSTSEQ_AUTO_DPI_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER +// Description : 1 = reset is controlled by the sequencer +// 0 = reset is controlled by rstseq_ctrl +#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_RESET 0x1 +#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_BITS 0x00000001 +#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_MSB 0 +#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_LSB 0 +#define RPI_MIPICFG_RSTSEQ_AUTO_BUSADAPTER_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_RSTSEQ_PARALLEL +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_RSTSEQ_PARALLEL_OFFSET 0x00000044 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BITS 0x00000007 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_RESET 0x00000006 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_CSI +// Description : Is this reset parallel (i.e. not part of the sequence) +#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_RESET 0x1 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_BITS 0x00000004 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_MSB 2 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_LSB 2 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_CSI_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_DPI +// Description : Is this reset parallel (i.e. not part of the sequence) +#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_RESET 0x1 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_BITS 0x00000002 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_MSB 1 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_LSB 1 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_DPI_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER +// Description : Is this reset parallel (i.e. not part of the sequence) +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_BITS 0x00000001 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_MSB 0 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_LSB 0 +#define RPI_MIPICFG_RSTSEQ_PARALLEL_BUSADAPTER_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_RSTSEQ_CTRL +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_RSTSEQ_CTRL_OFFSET 0x00000048 +#define RPI_MIPICFG_RSTSEQ_CTRL_BITS 0x00000007 +#define RPI_MIPICFG_RSTSEQ_CTRL_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_CTRL_CSI +// Description : 1 = keep the reset asserted +// 0 = keep the reset deasserted +// This is ignored if rstseq_auto=1 +#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_BITS 0x00000004 +#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_MSB 2 +#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_LSB 2 +#define RPI_MIPICFG_RSTSEQ_CTRL_CSI_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_CTRL_DPI +// Description : 1 = keep the reset asserted +// 0 = keep the reset deasserted +// This is ignored if rstseq_auto=1 +#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_BITS 0x00000002 +#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_MSB 1 +#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_LSB 1 +#define RPI_MIPICFG_RSTSEQ_CTRL_DPI_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER +// Description : 1 = keep the reset asserted +// 0 = keep the reset deasserted +// This is ignored if rstseq_auto=1 +#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_BITS 0x00000001 +#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_MSB 0 +#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_LSB 0 +#define RPI_MIPICFG_RSTSEQ_CTRL_BUSADAPTER_ACCESS "RW" +// ================================================================================ +// Register : RPI_MIPICFG_RSTSEQ_TRIG +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_RSTSEQ_TRIG_OFFSET 0x0000004c +#define RPI_MIPICFG_RSTSEQ_TRIG_BITS 0x00000007 +#define RPI_MIPICFG_RSTSEQ_TRIG_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_TRIG_CSI +// Description : Pulses the reset output +#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_BITS 0x00000004 +#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_MSB 2 +#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_LSB 2 +#define RPI_MIPICFG_RSTSEQ_TRIG_CSI_ACCESS "SC" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_TRIG_DPI +// Description : Pulses the reset output +#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_BITS 0x00000002 +#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_MSB 1 +#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_LSB 1 +#define RPI_MIPICFG_RSTSEQ_TRIG_DPI_ACCESS "SC" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER +// Description : Pulses the reset output +#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_BITS 0x00000001 +#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_MSB 0 +#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_LSB 0 +#define RPI_MIPICFG_RSTSEQ_TRIG_BUSADAPTER_ACCESS "SC" +// ================================================================================ +// Register : RPI_MIPICFG_RSTSEQ_DONE +// JTAG access : synchronous +// Description : None +#define RPI_MIPICFG_RSTSEQ_DONE_OFFSET 0x00000050 +#define RPI_MIPICFG_RSTSEQ_DONE_BITS 0x00000007 +#define RPI_MIPICFG_RSTSEQ_DONE_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_DONE_CSI +// Description : Indicates the current state of the reset +#define RPI_MIPICFG_RSTSEQ_DONE_CSI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_DONE_CSI_BITS 0x00000004 +#define RPI_MIPICFG_RSTSEQ_DONE_CSI_MSB 2 +#define RPI_MIPICFG_RSTSEQ_DONE_CSI_LSB 2 +#define RPI_MIPICFG_RSTSEQ_DONE_CSI_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_DONE_DPI +// Description : Indicates the current state of the reset +#define RPI_MIPICFG_RSTSEQ_DONE_DPI_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_DONE_DPI_BITS 0x00000002 +#define RPI_MIPICFG_RSTSEQ_DONE_DPI_MSB 1 +#define RPI_MIPICFG_RSTSEQ_DONE_DPI_LSB 1 +#define RPI_MIPICFG_RSTSEQ_DONE_DPI_ACCESS "RO" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER +// Description : Indicates the current state of the reset +#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_RESET 0x0 +#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_BITS 0x00000001 +#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_MSB 0 +#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_LSB 0 +#define RPI_MIPICFG_RSTSEQ_DONE_BUSADAPTER_ACCESS "RO" +// ================================================================================ +// Register : RPI_MIPICFG_DFTSS +// JTAG access : asynchronous +// Description : None +#define RPI_MIPICFG_DFTSS_OFFSET 0x00000054 +#define RPI_MIPICFG_DFTSS_BITS 0x0000001f +#define RPI_MIPICFG_DFTSS_RESET 0x00000000 +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DFTSS_JTAG_COPY +// Description : None +#define RPI_MIPICFG_DFTSS_JTAG_COPY_RESET 0x0 +#define RPI_MIPICFG_DFTSS_JTAG_COPY_BITS 0x00000010 +#define RPI_MIPICFG_DFTSS_JTAG_COPY_MSB 4 +#define RPI_MIPICFG_DFTSS_JTAG_COPY_LSB 4 +#define RPI_MIPICFG_DFTSS_JTAG_COPY_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY +// Description : None +#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_RESET 0x0 +#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_BITS 0x00000008 +#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_MSB 3 +#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_LSB 3 +#define RPI_MIPICFG_DFTSS_JTAG_ACCESS_ONLY_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS +// Description : None +#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_RESET 0x0 +#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_BITS 0x00000004 +#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_MSB 2 +#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_LSB 2 +#define RPI_MIPICFG_DFTSS_BYPASS_OUTSYNCS_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DFTSS_BYPASS_INSYNCS +// Description : None +#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_RESET 0x0 +#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_BITS 0x00000002 +#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_MSB 1 +#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_LSB 1 +#define RPI_MIPICFG_DFTSS_BYPASS_INSYNCS_ACCESS "RW" +// -------------------------------------------------------------------------------- +// Field : RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS +// Description : None +#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_RESET 0x0 +#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_BITS 0x00000001 +#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_MSB 0 +#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_LSB 0 +#define RPI_MIPICFG_DFTSS_BYPASS_RESETSYNCS_ACCESS "RW" + +#define CFG_WRITE(reg, val) writel((val), dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET)) +#define CFG_READ(reg) readl(dsi->hw_base[RP1DSI_HW_BLOCK_CFG] + (reg ## _OFFSET)) + +/* ------------------------------- DPHY setup stuff ------------------------ */ + +static void dphy_transaction(struct rp1_dsi *dsi, uint8_t test_code, uint8_t test_data) +{ + /* + * See pg 101 of mipi dphy bidir databook + * Assume we start with testclk high. + * Each APB write takes at least 10ns and we ignore TESTDOUT + * so there is no need for extra delays between the transitions. + */ + + DSI_WRITE(DSI_PHY_TST_CTRL1, test_code | DPHY_CTRL1_PHY_TESTEN_BITS); + DSI_WRITE(DSI_PHY_TST_CTRL0, 0); + DSI_READ(DSI_PHY_TST_CTRL1); /* XXX possibly not needed */ + DSI_WRITE(DSI_PHY_TST_CTRL1, test_data); + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); +} + +static uint8_t dphy_get_div(u32 refclk_khz, u32 vco_freq_khz, u32 *ptr_m, u32 *ptr_n) +{ + /* + * See pg 77-78 of dphy databook + * fvco = m/n * refclk + * with the limit + * 40MHz >= fREFCLK / N >= 5MHz + * M (multiplier) must be an even number between 2 and 300 + * N (input divider) must be an integer between 1 and 100 + * + * In practice, given a 50MHz reference clock, it can produce any + * multiple of 10MHz, 11.1111MHz, 12.5MHz, 14.286MHz or 16.667MHz + * with < 1% error for all frequencies above 495MHz. + */ + + static const u32 REF_DIVN_MAX = 40000u; + static const u32 REF_DIVN_MIN = 5000u; + u32 best_n, best_m, best_err = 0x7fffffff; + unsigned int n; + + for (n = 1 + refclk_khz / REF_DIVN_MAX; n * REF_DIVN_MIN <= refclk_khz && n < 100; ++n) { + u32 half_m = (n * vco_freq_khz + refclk_khz) / (2 * refclk_khz); + + if (half_m < 150) { + u32 f = (2 * half_m * refclk_khz) / n; + u32 err = (f > vco_freq_khz) ? f - vco_freq_khz : vco_freq_khz - f; + + if (err < best_err) { + best_n = n; + best_m = 2 * half_m; + best_err = err; + if (err == 0) + break; + } + } + } + + if (64 * best_err < vco_freq_khz) { /* tolerate small error */ + *ptr_n = best_n; + *ptr_m = best_m; + return 1; + } + return 0; +} + +struct hsfreq_range { + u16 mhz_max; + u8 hsfreqrange; + u8 clk_lp2hs; + u8 clk_hs2lp; + u8 data_lp2hs; /* excluding clk lane entry */ + u8 data_hs2lp; +}; + +/* See Table A-3 on page 258 of dphy databook */ +static const struct hsfreq_range hsfreq_table[] = { + { 89, 0b000000, 32, 20, 26, 13 }, + { 99, 0b010000, 35, 23, 28, 14 }, + { 109, 0b100000, 32, 22, 26, 13 }, + { 129, 0b000001, 31, 20, 27, 13 }, + { 139, 0b010001, 33, 22, 26, 14 }, + { 149, 0b100001, 33, 21, 26, 14 }, + { 169, 0b000010, 32, 20, 27, 13 }, + { 179, 0b010010, 36, 23, 30, 15 }, + { 199, 0b100010, 40, 22, 33, 15 }, + { 219, 0b000011, 40, 22, 33, 15 }, + { 239, 0b010011, 44, 24, 36, 16 }, + { 249, 0b100011, 48, 24, 38, 17 }, + { 269, 0b000100, 48, 24, 38, 17 }, + { 299, 0b010100, 50, 27, 41, 18 }, + { 329, 0b000101, 56, 28, 45, 18 }, + { 359, 0b010101, 59, 28, 48, 19 }, + { 399, 0b100101, 61, 30, 50, 20 }, + { 449, 0b000110, 67, 31, 55, 21 }, + { 499, 0b010110, 73, 31, 59, 22 }, + { 549, 0b000111, 79, 36, 63, 24 }, + { 599, 0b010111, 83, 37, 68, 25 }, + { 649, 0b001000, 90, 38, 73, 27 }, + { 699, 0b011000, 95, 40, 77, 28 }, + { 749, 0b001001, 102, 40, 84, 28 }, + { 799, 0b011001, 106, 42, 87, 30 }, + { 849, 0b101001, 113, 44, 93, 31 }, + { 899, 0b111001, 118, 47, 98, 32 }, + { 949, 0b001010, 124, 47, 102, 34 }, + { 999, 0b011010, 130, 49, 107, 35 }, + { 1049, 0b101010, 135, 51, 111, 37 }, + { 1099, 0b111010, 139, 51, 114, 38 }, + { 1149, 0b001011, 146, 54, 120, 40 }, + { 1199, 0b011011, 153, 57, 125, 41 }, + { 1249, 0b101011, 158, 58, 130, 42 }, + { 1299, 0b111011, 163, 58, 135, 44 }, + { 1349, 0b001100, 168, 60, 140, 45 }, + { 1399, 0b011100, 172, 64, 144, 47 }, + { 1449, 0b101100, 176, 65, 148, 48 }, + { 1500, 0b111100, 181, 66, 153, 50 }, +}; + +static void dphy_set_hsfreqrange(struct rp1_dsi *dsi, u32 freq_mhz) +{ + unsigned int i; + + if (freq_mhz < 80 || freq_mhz > 1500) + drm_err(dsi->drm, "DPHY: Frequency %u MHz out of range\n", + freq_mhz); + + for (i = 0; i < ARRAY_SIZE(hsfreq_table) - 1; i++) { + if (freq_mhz <= hsfreq_table[i].mhz_max) + break; + } + + dsi->hsfreq_index = i; + dphy_transaction(dsi, DPHY_HS_RX_CTRL_LANE0_OFFSET, + hsfreq_table[i].hsfreqrange << 1); +} + +static void dphy_configure_pll(struct rp1_dsi *dsi, u32 refclk_khz, u32 vco_freq_khz) +{ + u32 m = 0; + u32 n = 0; + + if (dphy_get_div(refclk_khz, vco_freq_khz, &m, &n)) { + dphy_set_hsfreqrange(dsi, vco_freq_khz / 1000); + /* Program m,n from registers */ + dphy_transaction(dsi, DPHY_PLL_DIV_CTRL_OFFSET, 0x30); + /* N (program N-1) */ + dphy_transaction(dsi, DPHY_PLL_INPUT_DIV_OFFSET, n - 1); + /* M[8:5] ?? */ + dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, 0x80 | ((m - 1) >> 5)); + /* M[4:0] (program M-1) */ + dphy_transaction(dsi, DPHY_PLL_LOOP_DIV_OFFSET, ((m - 1) & 0x1F)); + drm_dbg_driver(dsi->drm, + "DPHY: vco freq want %dkHz got %dkHz = %d * (%dkHz / %d), hsfreqrange = 0x%02x\r\n", + vco_freq_khz, refclk_khz * m / n, m, refclk_khz, + n, hsfreq_table[dsi->hsfreq_index].hsfreqrange); + } else { + drm_info(dsi->drm, + "rp1dsi: Error configuring DPHY PLL! %dkHz = %d * (%dkHz / %d)\r\n", + vco_freq_khz, m, refclk_khz, n); + } +} + +static void dphy_init_khz(struct rp1_dsi *dsi, u32 ref_freq, u32 vco_freq) +{ + /* Reset the PHY */ + DSI_WRITE(DSI_PHYRSTZ, 0); + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); + DSI_WRITE(DSI_PHY_TST_CTRL1, 0); + DSI_WRITE(DSI_PHY_TST_CTRL0, (DPHY_CTRL0_PHY_TESTCLK_BITS | DPHY_CTRL0_PHY_TESTCLR_BITS)); + udelay(1); + DSI_WRITE(DSI_PHY_TST_CTRL0, DPHY_CTRL0_PHY_TESTCLK_BITS); + udelay(1); + /* Since we are in DSI (not CSI2) mode here, start the PLL */ + dphy_configure_pll(dsi, ref_freq, vco_freq); + udelay(1); + /* Unreset */ + DSI_WRITE(DSI_PHYRSTZ, DSI_PHYRSTZ_SHUTDOWNZ_BITS); + udelay(1); + DSI_WRITE(DSI_PHYRSTZ, (DSI_PHYRSTZ_SHUTDOWNZ_BITS | DSI_PHYRSTZ_RSTZ_BITS)); + udelay(1); /* so we can see PLL coming up? */ +} + +void rp1dsi_mipicfg_setup(struct rp1_dsi *dsi) +{ + /* Select DSI rather than CSI-2 */ + CFG_WRITE(RPI_MIPICFG_CFG, 0); + /* Enable DSIDMA interrupt only */ + CFG_WRITE(RPI_MIPICFG_INTE, RPI_MIPICFG_INTE_DSI_DMA_BITS); +} + +static unsigned long rp1dsi_refclk_freq(struct rp1_dsi *dsi) +{ + unsigned long u; + + u = (dsi->clocks[RP1DSI_CLOCK_REF]) ? clk_get_rate(dsi->clocks[RP1DSI_CLOCK_REF]) : 0; + if (u < 1 || u >= (1ul << 30)) + u = 50000000ul; /* default XOSC frequency */ + return u; +} + +static void rp1dsi_dpiclk_start(struct rp1_dsi *dsi, unsigned int bpp, unsigned int lanes) +{ + unsigned long u; + + if (dsi->clocks[RP1DSI_CLOCK_DPI]) { + u = (dsi->clocks[RP1DSI_CLOCK_BYTE]) ? + clk_get_rate(dsi->clocks[RP1DSI_CLOCK_BYTE]) : 0; + drm_info(dsi->drm, + "rp1dsi: Nominal byte clock %lu; scale by %u/%u", + u, 4 * lanes, (bpp >> 1)); + if (u < 1 || u >= (1ul << 28)) + u = 72000000ul; /* default DUMMY frequency for byteclock */ + + clk_set_parent(dsi->clocks[RP1DSI_CLOCK_DPI], dsi->clocks[RP1DSI_CLOCK_BYTE]); + clk_set_rate(dsi->clocks[RP1DSI_CLOCK_DPI], (4 * lanes * u) / (bpp >> 1)); + clk_prepare_enable(dsi->clocks[RP1DSI_CLOCK_DPI]); + } +} + +static void rp1dsi_dpiclk_stop(struct rp1_dsi *dsi) +{ + if (dsi->clocks[RP1DSI_CLOCK_DPI]) + clk_disable_unprepare(dsi->clocks[RP1DSI_CLOCK_DPI]); +} + +/* Choose the internal on-the-bus DPI format, and DSI packing flag. */ +static u32 get_colorcode(enum mipi_dsi_pixel_format fmt) +{ + switch (fmt) { + case MIPI_DSI_FMT_RGB666: + return 0x104; + case MIPI_DSI_FMT_RGB666_PACKED: + return 0x003; + case MIPI_DSI_FMT_RGB565: + return 0x000; + case MIPI_DSI_FMT_RGB888: + return 0x005; + } + + /* This should be impossible as the format is validated in + * rp1dsi_host_attach + */ + WARN_ONCE(1, "Invalid colour format configured for DSI"); + return 0x005; +} + +void rp1dsi_dsi_setup(struct rp1_dsi *dsi, struct drm_display_mode const *mode) +{ + u32 timeout, mask, vid_mode_cfg; + u32 freq_khz; + unsigned int bpp = mipi_dsi_pixel_format_to_bpp(dsi->display_format); + + DSI_WRITE(DSI_PHY_IF_CFG, dsi->lanes - 1); + DSI_WRITE(DSI_DPI_CFG_POL, 0); + DSI_WRITE(DSI_GEN_VCID, dsi->vc); + DSI_WRITE(DSI_DPI_COLOR_CODING, get_colorcode(dsi->display_format)); + /* a conservative guess (LP escape is slow!) */ + DSI_WRITE(DSI_DPI_LP_CMD_TIM, 0x00100000); + + /* Drop to LP where possible */ + vid_mode_cfg = 0xbf00; + if (!(dsi->display_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) + vid_mode_cfg |= 0x01; + if (dsi->display_flags & MIPI_DSI_MODE_VIDEO_BURST) + vid_mode_cfg |= 0x02; + DSI_WRITE(DSI_VID_MODE_CFG, vid_mode_cfg); + + /* Use LP Escape Data signalling for all commands */ + DSI_WRITE(DSI_CMD_MODE_CFG, 0x10F7F00); + /* Select Command Mode */ + DSI_WRITE(DSI_MODE_CFG, 1); + /* XXX magic number */ + DSI_WRITE(DSI_TO_CNT_CFG, 0x02000200); + /* XXX magic number */ + DSI_WRITE(DSI_BTA_TO_CNT, 0x800); + + DSI_WRITE(DSI_VID_PKT_SIZE, mode->hdisplay); + DSI_WRITE(DSI_VID_NUM_CHUNKS, 0); + DSI_WRITE(DSI_VID_NULL_SIZE, 0); + + /* Note, unlike Argon firmware, here we DON'T consider sync to be concurrent with porch */ + DSI_WRITE(DSI_VID_HSA_TIME, + (bpp * (mode->hsync_end - mode->hsync_start)) / (8 * dsi->lanes)); + DSI_WRITE(DSI_VID_HBP_TIME, + (bpp * (mode->htotal - mode->hsync_end)) / (8 * dsi->lanes)); + DSI_WRITE(DSI_VID_HLINE_TIME, (bpp * mode->htotal) / (8 * dsi->lanes)); + DSI_WRITE(DSI_VID_VSA_LINES, (mode->vsync_end - mode->vsync_start)); + DSI_WRITE(DSI_VID_VBP_LINES, (mode->vtotal - mode->vsync_end)); + DSI_WRITE(DSI_VID_VFP_LINES, (mode->vsync_start - mode->vdisplay)); + DSI_WRITE(DSI_VID_VACTIVE_LINES, mode->vdisplay); + + freq_khz = (bpp * mode->clock) / dsi->lanes; + + dphy_init_khz(dsi, rp1dsi_refclk_freq(dsi) / 1000, freq_khz); + + DSI_WRITE(DSI_PHY_TMR_LPCLK_CFG, + (hsfreq_table[dsi->hsfreq_index].clk_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | + (hsfreq_table[dsi->hsfreq_index].clk_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); + DSI_WRITE(DSI_PHY_TMR_CFG, + (hsfreq_table[dsi->hsfreq_index].data_lp2hs << DSI_PHY_TMR_LP2HS_LSB) | + (hsfreq_table[dsi->hsfreq_index].data_hs2lp << DSI_PHY_TMR_HS2LP_LSB)); + + DSI_WRITE(DSI_CLKMGR_CFG, 0x00000505); + + /* Wait for PLL lock */ + for (timeout = (1 << 14); timeout != 0; --timeout) { + usleep_range(10, 50); + if (DSI_READ(DSI_PHY_STATUS) & (1 << 0)) + break; + } + if (timeout == 0) + drm_err(dsi->drm, "RP1DSI: Time out waiting for PLL\n"); + + DSI_WRITE(DSI_LPCLK_CTRL, 0x1); /* configure the requesthsclk */ + DSI_WRITE(DSI_PHY_TST_CTRL0, 0x2); + DSI_WRITE(DSI_PCKHDL_CFG, 1 << 2); /* allow bus turnaround */ + DSI_WRITE(DSI_PWR_UP, 0x1); /* power up */ + + /* Now it should be safe to start the external DPI clock divider */ + rp1dsi_dpiclk_start(dsi, bpp, dsi->lanes); + + /* Wait for all lane(s) to be in Stopstate */ + mask = (1 << 4); + if (dsi->lanes >= 2) + mask |= (1 << 7); + if (dsi->lanes >= 3) + mask |= (1 << 9); + if (dsi->lanes >= 4) + mask |= (1 << 11); + for (timeout = (1 << 10); timeout != 0; --timeout) { + usleep_range(10, 50); + if ((DSI_READ(DSI_PHY_STATUS) & mask) == mask) + break; + } + if (timeout == 0) + drm_err(dsi->drm, "RP1DSI: Time out waiting for lanes (%x %x)\n", + mask, DSI_READ(DSI_PHY_STATUS)); +} + +void rp1dsi_dsi_send(struct rp1_dsi *dsi, u32 hdr, int len, const u8 *buf) +{ + u32 val; + + /* Wait for both FIFOs empty */ + for (val = 256; val > 0; --val) { + if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) + break; + usleep_range(100, 150); + } + + /* Write payload (in 32-bit words) and header */ + for (; len > 0; len -= 4) { + val = *buf++; + if (len > 1) + val |= (*buf++) << 8; + if (len > 2) + val |= (*buf++) << 16; + if (len > 3) + val |= (*buf++) << 24; + DSI_WRITE(DSI_GEN_PLD_DATA, val); + } + DSI_WRITE(DSI_GEN_HDR, hdr); + + /* Wait for both FIFOs empty */ + for (val = 256; val > 0; --val) { + if ((DSI_READ(DSI_CMD_PKT_STATUS) & 0xF) == 0x5) + break; + usleep_range(100, 150); + } +} + +int rp1dsi_dsi_recv(struct rp1_dsi *dsi, int len, u8 *buf) +{ + int i, j; + u32 val; + + /* Wait until not busy and FIFO not empty */ + for (i = 1024; i > 0; --i) { + val = DSI_READ(DSI_CMD_PKT_STATUS); + if ((val & ((1 << 6) | (1 << 4))) == 0) + break; + usleep_range(100, 150); + } + if (i == 0) + return -EIO; + + for (i = 0; i < len; i += 4) { + /* Read fifo must not be empty before all bytes are read */ + if (DSI_READ(DSI_CMD_PKT_STATUS) & (1 << 4)) + break; + + val = DSI_READ(DSI_GEN_PLD_DATA); + for (j = 0; j < 4 && j + i < len; j++) + *buf++ = val >> (8 * j); + } + + return (i >= len) ? len : (i > 0) ? i : -EIO; +} + +void rp1dsi_dsi_stop(struct rp1_dsi *dsi) +{ + DSI_WRITE(DSI_MODE_CFG, 1); /* Return to Command Mode */ + DSI_WRITE(DSI_LPCLK_CTRL, 2); /* Stop the HS clock */ + DSI_WRITE(DSI_PWR_UP, 0x0); /* Power down host controller */ + DSI_WRITE(DSI_PHYRSTZ, 0); /* PHY into reset. */ + rp1dsi_dpiclk_stop(dsi); +} + +void rp1dsi_dsi_set_cmdmode(struct rp1_dsi *dsi, int mode) +{ + DSI_WRITE(DSI_MODE_CFG, mode); +}