drivers/gpu/drm/mxsfb/mxsfb_kms.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/mxsfb/mxsfb_kms.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/mxsfb/mxsfb_kms.c
Extension
.c
Size
21862 bytes
Lines
724
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

if (bus_format == MEDIA_BUS_FMT_FIXED) {
			dev_warn_once(drm->dev,
				      "Bridge does not provide bus format, assuming MEDIA_BUS_FMT_RGB888_1X24.\n"
				      "Please fix bridge driver by handling atomic_get_input_bus_fmts.\n");
			bus_format = MEDIA_BUS_FMT_RGB888_1X24;
		}
	}

	/* If there is no bridge, use bus format from connector */
	if (!bus_format && mxsfb->connector->display_info.num_bus_formats)
		bus_format = mxsfb->connector->display_info.bus_formats[0];

	/* If all else fails, default to RGB888_1X24 */
	if (!bus_format)
		bus_format = MEDIA_BUS_FMT_RGB888_1X24;

	mxsfb_crtc_mode_set_nofb(mxsfb, bridge_state, bus_format);

	/* Write cur_buf as well to avoid an initial corrupt frame */
	dma_addr = drm_fb_dma_get_gem_addr(new_pstate->fb, new_pstate, 0);
	if (dma_addr) {
		writel(dma_addr, mxsfb->base + mxsfb->devdata->cur_buf);
		writel(dma_addr, mxsfb->base + mxsfb->devdata->next_buf);
	}

	mxsfb_enable_controller(mxsfb);
}

static void mxsfb_crtc_atomic_disable(struct drm_crtc *crtc,
				      struct drm_atomic_commit *state)
{
	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);
	struct drm_device *drm = mxsfb->drm;
	struct drm_pending_vblank_event *event;

	mxsfb_disable_controller(mxsfb);

	spin_lock_irq(&drm->event_lock);
	event = crtc->state->event;
	if (event) {
		crtc->state->event = NULL;
		drm_crtc_send_vblank_event(crtc, event);
	}
	spin_unlock_irq(&drm->event_lock);

	drm_crtc_vblank_off(crtc);

	mxsfb_disable_axi_clk(mxsfb);
	pm_runtime_put_sync(drm->dev);
}

static int mxsfb_crtc_enable_vblank(struct drm_crtc *crtc)
{
	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);

	/* Clear and enable VBLANK IRQ */
	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_SET);

	return 0;
}

static void mxsfb_crtc_disable_vblank(struct drm_crtc *crtc)
{
	struct mxsfb_drm_private *mxsfb = to_mxsfb_drm_private(crtc->dev);

	/* Disable and clear VBLANK IRQ */
	writel(CTRL1_CUR_FRAME_DONE_IRQ_EN, mxsfb->base + LCDC_CTRL1 + REG_CLR);
	writel(CTRL1_CUR_FRAME_DONE_IRQ, mxsfb->base + LCDC_CTRL1 + REG_CLR);
}

static int mxsfb_crtc_set_crc_source(struct drm_crtc *crtc, const char *source)
{
	struct mxsfb_drm_private *mxsfb;

	if (!crtc)
		return -ENODEV;

	mxsfb = to_mxsfb_drm_private(crtc->dev);

	if (source && strcmp(source, "auto") == 0)
		mxsfb->crc_active = true;
	else if (!source)
		mxsfb->crc_active = false;
	else
		return -EINVAL;

	return 0;
}

Annotation

Implementation Notes