Exemplo n.º 1
0
static struct drm_framebuffer *
shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv,
		    struct drm_mode_fb_cmd2 *mode_cmd)
{
	const struct shmob_drm_format_info *format;

	format = shmob_drm_format_info(mode_cmd->pixel_format);
	if (format == NULL) {
		dev_dbg(dev->dev, "unsupported pixel format %08x\n",
			mode_cmd->pixel_format);
		return ERR_PTR(-EINVAL);
	}

	if (mode_cmd->pitches[0] & 7 || mode_cmd->pitches[0] >= 65536) {
		dev_dbg(dev->dev, "invalid pitch value %u\n",
			mode_cmd->pitches[0]);
		return ERR_PTR(-EINVAL);
	}

	if (format->yuv) {
		unsigned int chroma_cpp = format->bpp == 24 ? 2 : 1;

		if (mode_cmd->pitches[1] != mode_cmd->pitches[0] * chroma_cpp) {
			dev_dbg(dev->dev,
				"luma and chroma pitches do not match\n");
			return ERR_PTR(-EINVAL);
		}
	}

	return drm_fb_cma_create(dev, file_priv, mode_cmd);
}
Exemplo n.º 2
0
static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
				   struct drm_display_mode *mode,
				   struct drm_display_mode *adjusted_mode,
				   int x, int y,
				   struct drm_framebuffer *old_fb)
{
	struct shmob_drm_crtc *scrtc = to_shmob_crtc(crtc);
	struct shmob_drm_device *sdev = crtc->dev->dev_private;
	const struct sh_mobile_meram_cfg *mdata = sdev->pdata->meram;
	const struct shmob_drm_format_info *format;
	void *cache;

	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
	if (format == NULL) {
		dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n",
			crtc->primary->fb->pixel_format);
		return -EINVAL;
	}

	scrtc->format = format;
	scrtc->line_size = crtc->primary->fb->pitches[0];

	if (sdev->meram) {
		/* Enable MERAM cache if configured. We need to de-init
		 * configured ICBs before we can re-initialize them.
		 */
		if (scrtc->cache) {
			sh_mobile_meram_cache_free(sdev->meram, scrtc->cache);
			scrtc->cache = NULL;
		}

		cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
						    crtc->primary->fb->pitches[0],
						    adjusted_mode->vdisplay,
						    format->meram,
						    &scrtc->line_size);
		if (!IS_ERR(cache))
			scrtc->cache = cache;
	}

	shmob_drm_crtc_compute_base(scrtc, x, y);

	return 0;
}
Exemplo n.º 3
0
/*
 * shmob_drm_crtc_start - Configure and start the LCDC
 * @scrtc: the SH Mobile CRTC
 *
 * Configure and start the LCDC device. External devices (clocks, MERAM, panels,
 * ...) are not touched by this function.
 */
static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
{
	struct drm_crtc *crtc = &scrtc->crtc;
	struct shmob_drm_device *sdev = crtc->dev->dev_private;
	const struct shmob_drm_interface_data *idata = &sdev->pdata->iface;
	const struct shmob_drm_format_info *format;
	struct drm_device *dev = sdev->ddev;
	struct drm_plane *plane;
	u32 value;
	int ret;

	if (scrtc->started)
		return;

	format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
	if (WARN_ON(format == NULL))
		return;

	/* Enable clocks before accessing the hardware. */
	ret = shmob_drm_clk_on(sdev);
	if (ret < 0)
		return;

	/* Reset and enable the LCDC. */
	lcdc_write(sdev, LDCNT2R, lcdc_read(sdev, LDCNT2R) | LDCNT2R_BR);
	lcdc_wait_bit(sdev, LDCNT2R, LDCNT2R_BR, 0);
	lcdc_write(sdev, LDCNT2R, LDCNT2R_ME);

	/* Stop the LCDC first and disable all interrupts. */
	shmob_drm_crtc_start_stop(scrtc, false);
	lcdc_write(sdev, LDINTR, 0);

	/* Configure power supply, dot clocks and start them. */
	lcdc_write(sdev, LDPMR, 0);

	value = sdev->lddckr;
	if (idata->clk_div) {
		/* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider
		 * denominator.
		 */
		lcdc_write(sdev, LDDCKPAT1R, 0);
		lcdc_write(sdev, LDDCKPAT2R, (1 << (idata->clk_div / 2)) - 1);

		if (idata->clk_div == 1)
			value |= LDDCKR_MOSEL;
		else
			value |= idata->clk_div;
	}

	lcdc_write(sdev, LDDCKR, value);
	lcdc_write(sdev, LDDCKSTPR, 0);
	lcdc_wait_bit(sdev, LDDCKSTPR, ~0, 0);

	/* TODO: Setup SYS panel */

	/* Setup geometry, format, frame buffer memory and operation mode. */
	shmob_drm_crtc_setup_geometry(scrtc);

	/* TODO: Handle YUV colorspaces. Hardcode REC709 for now. */
	lcdc_write(sdev, LDDFR, format->lddfr | LDDFR_CF1);
	lcdc_write(sdev, LDMLSR, scrtc->line_size);
	lcdc_write(sdev, LDSA1R, scrtc->dma[0]);
	if (format->yuv)
		lcdc_write(sdev, LDSA2R, scrtc->dma[1]);
	lcdc_write(sdev, LDSM1R, 0);

	/* Word and long word swap. */
	switch (format->fourcc) {
	case DRM_FORMAT_RGB565:
	case DRM_FORMAT_NV21:
	case DRM_FORMAT_NV61:
	case DRM_FORMAT_NV42:
		value = LDDDSR_LS | LDDDSR_WS;
		break;
	case DRM_FORMAT_RGB888:
	case DRM_FORMAT_NV12:
	case DRM_FORMAT_NV16:
	case DRM_FORMAT_NV24:
		value = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS;
		break;
	case DRM_FORMAT_ARGB8888:
	default:
		value = LDDDSR_LS;
		break;
	}
	lcdc_write(sdev, LDDDSR, value);

	/* Setup planes. */
	drm_for_each_legacy_plane(plane, dev) {
		if (plane->crtc == crtc)
			shmob_drm_plane_setup(plane);
	}

	/* Enable the display output. */
	lcdc_write(sdev, LDCNT1R, LDCNT1R_DE);

	shmob_drm_crtc_start_stop(scrtc, true);

	scrtc->started = true;
}