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); }
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; }
/* * 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; }