// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2015 Broadcom
*/
/**
* DOC: VC4 CRTC module
*
* In VC4, the Pixel Valve is what most closely corresponds to the
* DRM's concept of a CRTC. The PV generates video timings from the
* encoder's clock plus its configuration. It pulls scaled pixels from
* the HVS at that timing, and feeds it to the encoder.
*
* However, the DRM CRTC also collects the configuration of all the
* DRM planes attached to it. As a result, the CRTC is also
* responsible for writing the display list for the HVS channel that
* the CRTC will use.
*
* The 2835 has 3 different pixel valves. pv0 in the audio power
* domain feeds DSI0 or DPI, while pv1 feeds DS1 or SMI. pv2 in the
* image domain can feed either HDMI or the SDTV controller. The
* pixel valve chooses from the CPRMAN clocks (HSM for HDMI, VEC for
* SDTV, etc.) according to which output type is chosen in the mux.
*
* For power management, the pixel valve's registers are all clocked
* by the AXI clock, while the timings and FIFOs make use of the
* output-specific clock. Since the encoders also directly consume
* the CPRMAN clocks, and know what timings they need, they are the
* ones that set the clock.
*/
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_vblank.h>
#include "vc4_drv.h"
#include "vc4_hdmi.h"
#include "vc4_regs.h"
#define HVS_FIFO_LATENCY_PIX 6
#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
static const struct debugfs_reg32 crtc_regs[] = {
VC4_REG32(PV_CONTROL),
VC4_REG32(PV_V_CONTROL),
VC4_REG32(PV_VSYNCD_EVEN),
VC4_REG32(PV_HORZA),
VC4_REG32(PV_HORZB),
VC4_REG32(PV_VERTA),
VC4_REG32(PV_VERTB),
VC4_REG32(PV_VERTA_EVEN),
VC4_REG32(PV_VERTB_EVEN),
VC4_REG32(PV_INTEN),
VC4_REG32(PV_INTSTAT),
VC4_REG32(PV_STAT),
VC4_REG32(PV_HACT_ACT),
};
static unsigned int
vc4_crtc_get_cob_allocation(struct vc4_dev *vc4, unsigned int channel)
{
struct vc4_hvs *hvs = vc4->hvs;
u32 dispbase = HVS_READ(SCALER_DISPBASEX(channel));
/* Top/base are supposed to be 4-pixel aligned, but the
* Raspberry Pi firmware fills the low bits (which are
* presumably ignored).
*/
u32 top = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_TOP) & ~3;
u32 base = VC4_GET_FIELD(dispbase, SCALER_DISPBASEX_BASE) & ~3;
return top - base + 4;
}
static bool vc4_crtc_get_scanout_position(struct drm_crtc *crtc,
bool in_vblank_irq,
int *vpos, int *hpos,
ktime_t *stime, ktime_t *etime,
const struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
struct