drivers/gpu/drm/nouveau/dispnv04/tvnv04.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
Extension
.c
Size
7606 bytes
Lines
255
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

#include "nouveau_drv.h"
#include "nouveau_reg.h"
#include "nouveau_encoder.h"
#include "nouveau_connector.h"
#include "nouveau_crtc.h"
#include "hw.h"
#include <drm/drm_modeset_helper_vtables.h>

#include <dispnv04/i2c/ch7006.h>

static struct nvkm_i2c_bus_probe nv04_tv_encoder_info[] = {
	{
		{
			I2C_BOARD_INFO("ch7006", 0x75),
			.platform_data = &(struct ch7006_encoder_params) {
				CH7006_FORMAT_RGB24m12I, CH7006_CLOCK_MASTER,
				0, 0, 0,
				CH7006_SYNC_SLAVE, CH7006_SYNC_SEPARATED,
				CH7006_POUT_3_3V, CH7006_ACTIVE_HSYNC
			}
		},
		0
	},
	{ }
};

int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nvkm_i2c *i2c = nvxx_i2c(drm);
	struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, i2c_index);
	if (bus) {
		return nvkm_i2c_bus_probe(bus, "TV encoder",
					  nv04_tv_encoder_info,
					  NULL, NULL);
	}
	return -ENODEV;
}


#define PLLSEL_TV_CRTC1_MASK				\
	(NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK1		\
	 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK1)
#define PLLSEL_TV_CRTC2_MASK				\
	(NV_PRAMDAC_PLL_COEFF_SELECT_TV_VSCLK2		\
	 | NV_PRAMDAC_PLL_COEFF_SELECT_TV_PCLK2)

static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
{
	struct drm_device *dev = encoder->dev;
	struct nouveau_drm *drm = nouveau_drm(dev);
	struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
	struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
	uint8_t crtc1A;

	NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
		 mode, nv_encoder->dcb->index);

	state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK);

	if (mode == DRM_MODE_DPMS_ON) {
		int head = nouveau_crtc(encoder->crtc)->index;
		crtc1A = NVReadVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX);

		state->pllsel |= head ? PLLSEL_TV_CRTC2_MASK :
					PLLSEL_TV_CRTC1_MASK;

		/* Inhibit hsync */
		crtc1A |= 0x80;

		NVWriteVgaCrtc(dev, head, NV_CIO_CRE_RPC1_INDEX, crtc1A);
	}

	NVWriteRAMDAC(dev, 0, NV_PRAMDAC_PLL_COEFF_SELECT, state->pllsel);

	get_encoder_i2c_funcs(encoder)->dpms(encoder, mode);
}

static void nv04_tv_bind(struct drm_device *dev, int head, bool bind)
{
	struct nv04_crtc_reg *state = &nv04_display(dev)->mode_reg.crtc_reg[head];

	state->tv_setup = 0;

	if (bind)
		state->CRTC[NV_CIO_CRE_49] |= 0x10;
	else
		state->CRTC[NV_CIO_CRE_49] &= ~0x10;

	NVWriteVgaCrtc(dev, head, NV_CIO_CRE_LCD__INDEX,

Annotation

Implementation Notes