diff options
Diffstat (limited to 'drivers/gpu/drm/ingenic/ingenic-drm-drv.c')
-rw-r--r-- | drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 75 |
1 files changed, 71 insertions, 4 deletions
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c index b4943a56be09..dcf44cb00821 100644 --- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c +++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c @@ -6,6 +6,7 @@ #include "ingenic-drm.h" +#include <linux/bitfield.h> #include <linux/component.h> #include <linux/clk.h> #include <linux/dma-mapping.h> @@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc { u32 addr; u32 id; u32 cmd; + /* extended hw descriptor for jz4780 */ + u32 offsize; + u32 pagewidth; + u32 cpos; + u32 dessize; } __aligned(16); struct ingenic_dma_hwdescs { @@ -59,7 +65,10 @@ struct ingenic_dma_hwdescs { struct jz_soc_info { bool needs_dev_clk; bool has_osd; + bool has_alpha; bool map_noncoherent; + bool use_extended_hwdesc; + bool plane_f0_not_working; unsigned int max_width, max_height; const u32 *formats_f0, *formats_f1; unsigned int num_formats_f0, num_formats_f1; @@ -173,7 +182,6 @@ static const struct regmap_config ingenic_drm_regmap_config = { .val_bits = 32, .reg_stride = 4, - .max_register = JZ_REG_LCD_SIZE1, .writeable_reg = ingenic_drm_writeable_reg, }; @@ -447,6 +455,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; + if (priv->soc_info->plane_f0_not_working && plane == &priv->f0) + return -EINVAL; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); if (WARN_ON(!crtc_state)) @@ -663,6 +674,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); hwdesc->next = dma_hwdesc_addr(priv, next_id); + if (priv->soc_info->use_extended_hwdesc) { + hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; + + /* Extended 8-byte descriptor */ + hwdesc->cpos = 0; + hwdesc->offsize = 0; + hwdesc->pagewidth = 0; + + switch (newstate->fb->format->format) { + case DRM_FORMAT_XRGB1555: + hwdesc->cpos |= JZ_LCD_CPOS_RGB555; + fallthrough; + case DRM_FORMAT_RGB565: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; + break; + case DRM_FORMAT_XRGB8888: + hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; + break; + } + hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << + JZ_LCD_CPOS_COEFFICIENT_OFFSET); + hwdesc->dessize = + (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) | + FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | + FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); + } + if (drm_atomic_crtc_needs_modeset(crtc_state)) { fourcc = newstate->fb->format->format; @@ -694,6 +732,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; } + if (priv->soc_info->use_extended_hwdesc) + cfg |= JZ_LCD_CFG_DESCRIPTOR_8; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; if (mode->flags & DRM_MODE_FLAG_NVSYNC) @@ -1011,9 +1052,12 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) struct ingenic_drm_bridge *ib; struct drm_device *drm; void __iomem *base; + struct resource *res; + struct regmap_config regmap_config; long parent_rate; unsigned int i, clone_mask = 0; int ret, irq; + u32 osdc = 0; soc_info = of_device_get_match_data(dev); if (!soc_info) { @@ -1056,14 +1100,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; - base = devm_platform_ioremap_resource(pdev, 0); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) { dev_err(dev, "Failed to get memory resource\n"); return PTR_ERR(base); } + regmap_config = ingenic_drm_regmap_config; + regmap_config.max_register = res->end - res->start; priv->map = devm_regmap_init_mmio(dev, base, - &ingenic_drm_regmap_config); + ®map_config); if (IS_ERR(priv->map)) { dev_err(dev, "Failed to create regmap\n"); return PTR_ERR(priv->map); @@ -1269,7 +1315,10 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) /* Enable OSD if available */ if (soc_info->has_osd) - regmap_write(priv->map, JZ_REG_LCD_OSDC, JZ_LCD_OSDC_OSDEN); + osdc |= JZ_LCD_OSDC_OSDEN; + if (soc_info->has_alpha) + osdc |= JZ_LCD_OSDC_ALPHAEN; + regmap_write(priv->map, JZ_REG_LCD_OSDC, osdc); mutex_init(&priv->clk_mutex); priv->clock_nb.notifier_call = ingenic_drm_update_pixclk; @@ -1465,10 +1514,25 @@ static const struct jz_soc_info jz4770_soc_info = { .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), }; +static const struct jz_soc_info jz4780_soc_info = { + .needs_dev_clk = true, + .has_osd = true, + .has_alpha = true, + .use_extended_hwdesc = true, + .plane_f0_not_working = true, /* REVISIT */ + .max_width = 4096, + .max_height = 2048, + .formats_f1 = jz4770_formats_f1, + .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), + .formats_f0 = jz4770_formats_f0, + .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), +}; + static const struct of_device_id ingenic_drm_of_match[] = { { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, + { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); @@ -1487,6 +1551,9 @@ static int ingenic_drm_init(void) { int err; + if (drm_firmware_drivers_only()) + return -ENODEV; + if (IS_ENABLED(CONFIG_DRM_INGENIC_IPU)) { err = platform_driver_register(ingenic_ipu_driver_ptr); if (err) |