diff options
Diffstat (limited to 'drivers/gpu/drm/fsl-dcu')
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/Kconfig | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 49 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 87 | ||||
-rw-r--r-- | drivers/gpu/drm/fsl-dcu/fsl_tcon.c | 1 |
10 files changed, 139 insertions, 84 deletions
diff --git a/drivers/gpu/drm/fsl-dcu/Kconfig b/drivers/gpu/drm/fsl-dcu/Kconfig index b9c714de6..14a72c4c4 100644 --- a/drivers/gpu/drm/fsl-dcu/Kconfig +++ b/drivers/gpu/drm/fsl-dcu/Kconfig @@ -5,12 +5,7 @@ config DRM_FSL_DCU select BACKLIGHT_LCD_SUPPORT select DRM_KMS_HELPER select DRM_KMS_CMA_HELPER - select DRM_KMS_FB_HELPER select DRM_PANEL - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS select REGMAP_MMIO select VIDEOMODE_HELPERS help diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 89c0084c2..3371635cd 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -22,20 +22,21 @@ #include "fsl_dcu_drm_drv.h" #include "fsl_dcu_drm_plane.h" -static void fsl_dcu_drm_crtc_atomic_begin(struct drm_crtc *crtc, +static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { -} + struct drm_pending_vblank_event *event = crtc->state->event; -static int fsl_dcu_drm_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - return 0; -} + if (event) { + crtc->state->event = NULL; -static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, - struct drm_crtc_state *old_crtc_state) -{ + spin_lock_irq(&crtc->dev->event_lock); + if (drm_crtc_vblank_get(crtc) == 0) + drm_crtc_arm_vblank_event(crtc, event); + else + drm_crtc_send_vblank_event(crtc, event); + spin_unlock_irq(&crtc->dev->event_lock); + } } static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) @@ -43,6 +44,8 @@ static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + drm_crtc_vblank_off(crtc); + regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, DCU_MODE_DCU_MODE_MASK, DCU_MODE_DCU_MODE(DCU_MODE_OFF)); @@ -60,6 +63,8 @@ static void fsl_dcu_drm_crtc_enable(struct drm_crtc *crtc) DCU_MODE_DCU_MODE(DCU_MODE_NORMAL)); regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, DCU_UPDATE_MODE_READREG); + + drm_crtc_vblank_on(crtc); } static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) @@ -117,8 +122,6 @@ static void fsl_dcu_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) } static const struct drm_crtc_helper_funcs fsl_dcu_drm_crtc_helper_funcs = { - .atomic_begin = fsl_dcu_drm_crtc_atomic_begin, - .atomic_check = fsl_dcu_drm_crtc_atomic_check, .atomic_flush = fsl_dcu_drm_crtc_atomic_flush, .disable = fsl_dcu_drm_disable_crtc, .enable = fsl_dcu_drm_crtc_enable, @@ -138,9 +141,10 @@ int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) { struct drm_plane *primary; struct drm_crtc *crtc = &fsl_dev->crtc; - unsigned int i, j, reg_num; int ret; + fsl_dcu_drm_init_planes(fsl_dev->drm); + primary = fsl_dcu_drm_primary_create_plane(fsl_dev->drm); if (!primary) return -ENOMEM; @@ -154,19 +158,5 @@ int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); - if (!strcmp(fsl_dev->soc->name, "ls1021a")) - reg_num = LS1021A_LAYER_REG_NUM; - else - reg_num = VF610_LAYER_REG_NUM; - for (i = 0; i < fsl_dev->soc->total_layer; i++) { - for (j = 1; j <= reg_num; j++) - regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0); - } - regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, - DCU_MODE_DCU_MODE_MASK, - DCU_MODE_DCU_MODE(DCU_MODE_OFF)); - regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, - DCU_UPDATE_MODE_READREG); - return 0; } diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index dc723f7ea..7882387f9 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -11,6 +11,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/console.h> #include <linux/io.h> #include <linux/mfd/syscon.h> #include <linux/mm.h> @@ -22,6 +23,7 @@ #include <linux/regmap.h> #include <drm/drmP.h> +#include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_cma_helper.h> #include <drm/drm_gem_cma_helper.h> @@ -42,10 +44,8 @@ static const struct regmap_config fsl_dcu_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .cache_type = REGCACHE_FLAT, .volatile_reg = fsl_dcu_drm_is_volatile_reg, - .max_register = 0x11fc, }; static int fsl_dcu_drm_irq_init(struct drm_device *dev) @@ -199,7 +199,7 @@ static struct drm_driver fsl_dcu_drm_driver = { .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = fsl_dcu_drm_enable_vblank, .disable_vblank = fsl_dcu_drm_disable_vblank, - .gem_free_object = drm_gem_cma_free_object, + .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, @@ -229,11 +229,26 @@ static int fsl_dcu_drm_pm_suspend(struct device *dev) if (!fsl_dev) return 0; + disable_irq(fsl_dev->irq); drm_kms_helper_poll_disable(fsl_dev->drm); - regcache_cache_only(fsl_dev->regmap, true); - regcache_mark_dirty(fsl_dev->regmap); - clk_disable(fsl_dev->clk); - clk_unprepare(fsl_dev->clk); + + console_lock(); + drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 1); + console_unlock(); + + fsl_dev->state = drm_atomic_helper_suspend(fsl_dev->drm); + if (IS_ERR(fsl_dev->state)) { + console_lock(); + drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0); + console_unlock(); + + drm_kms_helper_poll_enable(fsl_dev->drm); + enable_irq(fsl_dev->irq); + return PTR_ERR(fsl_dev->state); + } + + clk_disable_unprepare(fsl_dev->pix_clk); + clk_disable_unprepare(fsl_dev->clk); return 0; } @@ -246,21 +261,27 @@ static int fsl_dcu_drm_pm_resume(struct device *dev) if (!fsl_dev) return 0; - ret = clk_enable(fsl_dev->clk); + ret = clk_prepare_enable(fsl_dev->clk); if (ret < 0) { dev_err(dev, "failed to enable dcu clk\n"); - clk_unprepare(fsl_dev->clk); return ret; } - ret = clk_prepare(fsl_dev->clk); + + ret = clk_prepare_enable(fsl_dev->pix_clk); if (ret < 0) { - dev_err(dev, "failed to prepare dcu clk\n"); + dev_err(dev, "failed to enable pix clk\n"); return ret; } + fsl_dcu_drm_init_planes(fsl_dev->drm); + drm_atomic_helper_resume(fsl_dev->drm, fsl_dev->state); + + console_lock(); + drm_fbdev_cma_set_suspend(fsl_dev->fbdev, 0); + console_unlock(); + drm_kms_helper_poll_enable(fsl_dev->drm); - regcache_cache_only(fsl_dev->regmap, false); - regcache_sync(fsl_dev->regmap); + enable_irq(fsl_dev->irq); return 0; } @@ -274,12 +295,14 @@ static const struct fsl_dcu_soc_data fsl_dcu_ls1021a_data = { .name = "ls1021a", .total_layer = 16, .max_layer = 4, + .layer_regs = LS1021A_LAYER_REG_NUM, }; static const struct fsl_dcu_soc_data fsl_dcu_vf610_data = { .name = "vf610", .total_layer = 64, .max_layer = 6, + .layer_regs = VF610_LAYER_REG_NUM, }; static const struct of_device_id fsl_dcu_of_match[] = { diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h index c275f900f..3b371fe74 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h @@ -175,6 +175,7 @@ struct fsl_dcu_soc_data { unsigned int total_layer; /*max layer number DCU supported*/ unsigned int max_layer; + unsigned int layer_regs; }; struct fsl_dcu_drm_device { @@ -193,6 +194,7 @@ struct fsl_dcu_drm_device { struct drm_encoder encoder; struct fsl_dcu_drm_connector connector; const struct fsl_dcu_soc_data *soc; + struct drm_atomic_state *state; }; void fsl_dcu_fbdev_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c index c564ec612..d9d6cc1c8 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_kms.c @@ -37,23 +37,22 @@ int fsl_dcu_drm_modeset_init(struct fsl_dcu_drm_device *fsl_dev) ret = fsl_dcu_drm_crtc_create(fsl_dev); if (ret) - return ret; + goto err; ret = fsl_dcu_drm_encoder_create(fsl_dev, &fsl_dev->crtc); if (ret) - goto fail_encoder; + goto err; - ret = fsl_dcu_drm_connector_create(fsl_dev, &fsl_dev->encoder); + ret = fsl_dcu_create_outputs(fsl_dev); if (ret) - goto fail_connector; + goto err; drm_mode_config_reset(fsl_dev->drm); drm_kms_helper_poll_init(fsl_dev->drm); return 0; -fail_encoder: - fsl_dev->crtc.funcs->destroy(&fsl_dev->crtc); -fail_connector: - fsl_dev->encoder.funcs->destroy(&fsl_dev->encoder); + +err: + drm_mode_config_cleanup(fsl_dev->drm); return ret; } diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h index 7093109fb..5a7b88e19 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_output.h @@ -25,9 +25,8 @@ to_fsl_dcu_connector(struct drm_connector *con) : NULL; } -int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, - struct drm_encoder *encoder); int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device *fsl_dev, struct drm_crtc *crtc); +int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev); #endif /* __FSL_DCU_DRM_CONNECTOR_H__ */ diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c index 274558b3b..e50467a0d 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.c @@ -217,6 +217,22 @@ static const u32 fsl_dcu_drm_plane_formats[] = { DRM_FORMAT_YUV422, }; +void fsl_dcu_drm_init_planes(struct drm_device *dev) +{ + struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; + int i, j; + + for (i = 0; i < fsl_dev->soc->total_layer; i++) { + for (j = 1; j <= fsl_dev->soc->layer_regs; j++) + regmap_write(fsl_dev->regmap, DCU_CTRLDESCLN(i, j), 0); + } + regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_DCU_MODE_MASK, + DCU_MODE_DCU_MODE(DCU_MODE_OFF)); + regmap_write(fsl_dev->regmap, DCU_UPDATE_MODE, + DCU_UPDATE_MODE_READREG); +} + struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev) { struct drm_plane *primary; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h index d657f088d..8ee45f813 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_plane.h @@ -12,6 +12,7 @@ #ifndef __FSL_DCU_DRM_PLANE_H__ #define __FSL_DCU_DRM_PLANE_H__ +void fsl_dcu_drm_init_planes(struct drm_device *dev); struct drm_plane *fsl_dcu_drm_primary_create_plane(struct drm_device *dev); #endif /* __FSL_DCU_DRM_PLANE_H__ */ diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c index 98c998da9..26edcc899 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c @@ -10,6 +10,7 @@ */ #include <linux/backlight.h> +#include <linux/of_graph.h> #include <drm/drmP.h> #include <drm/drm_atomic_helper.h> @@ -102,14 +103,6 @@ static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = { .reset = drm_atomic_helper_connector_reset, }; -static struct drm_encoder * -fsl_dcu_drm_connector_best_encoder(struct drm_connector *connector) -{ - struct fsl_dcu_drm_connector *fsl_con = to_fsl_dcu_connector(connector); - - return fsl_con->encoder; -} - static int fsl_dcu_drm_connector_get_modes(struct drm_connector *connector) { struct fsl_dcu_drm_connector *fsl_connector; @@ -136,17 +129,16 @@ static int fsl_dcu_drm_connector_mode_valid(struct drm_connector *connector, } static const struct drm_connector_helper_funcs connector_helper_funcs = { - .best_encoder = fsl_dcu_drm_connector_best_encoder, .get_modes = fsl_dcu_drm_connector_get_modes, .mode_valid = fsl_dcu_drm_connector_mode_valid, }; -int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, - struct drm_encoder *encoder) +static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device *fsl_dev, + struct drm_panel *panel) { + struct drm_encoder *encoder = &fsl_dev->encoder; struct drm_connector *connector = &fsl_dev->connector.base; struct drm_mode_config *mode_config = &fsl_dev->drm->mode_config; - struct device_node *panel_node; int ret; fsl_dev->connector.encoder = encoder; @@ -170,21 +162,7 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, mode_config->dpms_property, DRM_MODE_DPMS_OFF); - panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0); - if (!panel_node) { - dev_err(fsl_dev->dev, "fsl,panel property not found\n"); - ret = -ENODEV; - goto err_sysfs; - } - - fsl_dev->connector.panel = of_drm_find_panel(panel_node); - if (!fsl_dev->connector.panel) { - ret = -EPROBE_DEFER; - goto err_panel; - } - of_node_put(panel_node); - - ret = drm_panel_attach(fsl_dev->connector.panel, connector); + ret = drm_panel_attach(panel, connector); if (ret) { dev_err(fsl_dev->dev, "failed to attach panel\n"); goto err_sysfs; @@ -192,11 +170,62 @@ int fsl_dcu_drm_connector_create(struct fsl_dcu_drm_device *fsl_dev, return 0; -err_panel: - of_node_put(panel_node); err_sysfs: drm_connector_unregister(connector); err_cleanup: drm_connector_cleanup(connector); return ret; } + +static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev, + const struct of_endpoint *ep) +{ + struct drm_bridge *bridge; + struct device_node *np; + + np = of_graph_get_remote_port_parent(ep->local_node); + + fsl_dev->connector.panel = of_drm_find_panel(np); + if (fsl_dev->connector.panel) { + of_node_put(np); + return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); + } + + bridge = of_drm_find_bridge(np); + of_node_put(np); + if (!bridge) + return -ENODEV; + + fsl_dev->encoder.bridge = bridge; + bridge->encoder = &fsl_dev->encoder; + + return drm_bridge_attach(fsl_dev->drm, bridge); +} + +int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev) +{ + struct of_endpoint ep; + struct device_node *ep_node, *panel_node; + int ret; + + /* This is for backward compatibility */ + panel_node = of_parse_phandle(fsl_dev->np, "fsl,panel", 0); + if (panel_node) { + fsl_dev->connector.panel = of_drm_find_panel(panel_node); + of_node_put(panel_node); + if (!fsl_dev->connector.panel) + return -EPROBE_DEFER; + return fsl_dcu_attach_panel(fsl_dev, fsl_dev->connector.panel); + } + + ep_node = of_graph_get_next_endpoint(fsl_dev->np, NULL); + if (!ep_node) + return -ENODEV; + + ret = of_graph_parse_endpoint(ep_node, &ep); + of_node_put(ep_node); + if (ret) + return -ENODEV; + + return fsl_dcu_attach_endpoint(fsl_dev, &ep); +} diff --git a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c index bbe34f1c0..bca09ea24 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_tcon.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_tcon.c @@ -92,6 +92,7 @@ struct fsl_tcon *fsl_tcon_init(struct device *dev) goto err_node_put; } + of_node_put(np); clk_prepare_enable(tcon->ipg_clk); dev_info(dev, "Using TCON in bypass mode\n"); |