#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
#include <linux/component.h>
#include <linux/fence.h>
#include <linux/console.h>
struct drm_plane_state *primary_state;
struct drm_display_mode *mode = NULL;
const struct drm_connector_helper_funcs *funcs;
+ const struct drm_encoder_helper_funcs *encoder_funcs;
bool is_crtc_enabled = true;
int hdisplay, vdisplay;
int fb_width, fb_height;
if (funcs->loader_protect)
funcs->loader_protect(connector, true);
connector->loader_protect = true;
+ encoder_funcs = conn_state->best_encoder->helper_private;
+ if (encoder_funcs->loader_protect)
+ encoder_funcs->loader_protect(conn_state->best_encoder, true);
+ conn_state->best_encoder->loader_protect = true;
num_modes = connector->funcs->fill_modes(connector, 4096, 4096);
if (!num_modes) {
dev_err(drm_dev->dev, "connector[%s] can't found any modes\n",
if (funcs->loader_protect)
funcs->loader_protect(connector, false);
connector->loader_protect = false;
+ if (encoder_funcs->loader_protect)
+ encoder_funcs->loader_protect(conn_state->best_encoder, false);
+ conn_state->best_encoder->loader_protect = false;
return ret;
}
static void show_loader_logo(struct drm_device *drm_dev)
{
- struct drm_atomic_state *state;
+ struct drm_atomic_state *state, *old_state;
struct device_node *np = drm_dev->dev->of_node;
struct drm_mode_config *mode_config = &drm_dev->mode_config;
struct device_node *root, *route;
goto err_free_state;
}
+ old_state = drm_atomic_helper_duplicate_state(drm_dev,
+ mode_config->acquire_ctx);
+ if (IS_ERR(old_state)) {
+ dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
+ ret = PTR_ERR_OR_ZERO(old_state);
+ goto err_free_state;
+ }
+
/*
* The state save initial devices status, swap the state into
* drm deivces as old state, so if new state come, can compare
if (IS_ERR(state)) {
dev_err(drm_dev->dev, "failed to duplicate atomic state\n");
ret = PTR_ERR_OR_ZERO(state);
- goto err_unlock;
+ goto err_free_old_state;
}
state->acquire_ctx = mode_config->acquire_ctx;
list_for_each_entry(set, &mode_set_list, head)
*/
WARN_ON(ret == -EDEADLK);
- if (ret)
- goto err_free_state;
+ if (ret) {
+ /*
+ * restore display status if atomic commit failed.
+ */
+ drm_atomic_helper_swap_state(drm_dev, old_state);
+ goto err_free_old_state;
+ }
rockchip_free_loader_memory(drm_dev);
+ drm_atomic_state_free(old_state);
drm_modeset_unlock_all(drm_dev);
return;
+err_free_old_state:
+ drm_atomic_state_free(old_state);
err_free_state:
drm_atomic_state_free(state);
err_unlock:
if (ret)
dev_err(drm_dev->dev, "failed to show loader logo\n");
}
+
+static const char *const loader_protect_clocks[] __initconst = {
+ "hclk_vio",
+ "aclk_vio",
+ "aclk_vio0",
+};
+
+static struct clk **loader_clocks __initdata;
+static int __init rockchip_clocks_loader_protect(void)
+{
+ int nclocks = ARRAY_SIZE(loader_protect_clocks);
+ struct clk *clk;
+ int i;
+
+ loader_clocks = kcalloc(nclocks, sizeof(void *), GFP_KERNEL);
+ if (!loader_clocks)
+ return -ENOMEM;
+
+ for (i = 0; i < nclocks; i++) {
+ clk = __clk_lookup(loader_protect_clocks[i]);
+
+ if (clk) {
+ loader_clocks[i] = clk;
+ clk_prepare_enable(clk);
+ }
+ }
+
+ return 0;
+}
+fs_initcall(rockchip_clocks_loader_protect);
+
+static int __init rockchip_clocks_loader_unprotect(void)
+{
+ int i;
+
+ if (!loader_clocks)
+ return -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(loader_protect_clocks); i++) {
+ struct clk *clk = loader_clocks[i];
+
+ if (clk)
+ clk_disable_unprepare(clk);
+ }
+ kfree(loader_clocks);
+
+ return 0;
+}
+late_initcall_sync(rockchip_clocks_loader_unprotect);
#endif
/*
struct rockchip_drm_private *priv = drm_dev->dev_private;
int ret;
+ if (!priv->domain)
+ return 0;
+
mutex_lock(&priv->mm_lock);
ret = drm_mm_dump_table(s, &priv->mm);
}
#endif
+static int rockchip_drm_create_properties(struct drm_device *dev)
+{
+ struct drm_property *prop;
+ struct rockchip_drm_private *private = dev->dev_private;
+ const struct drm_prop_enum_list cabc_mode_enum_list[] = {
+ { ROCKCHIP_DRM_CABC_MODE_DISABLE, "Disable" },
+ { ROCKCHIP_DRM_CABC_MODE_NORMAL, "Normal" },
+ { ROCKCHIP_DRM_CABC_MODE_LOWPOWER, "LowPower" },
+ { ROCKCHIP_DRM_CABC_MODE_USERSPACE, "Userspace" },
+ };
+
+ prop = drm_property_create_enum(dev, 0, "CABC_MODE", cabc_mode_enum_list,
+ ARRAY_SIZE(cabc_mode_enum_list));
+
+ private->cabc_mode_property = prop;
+
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB, "CABC_LUT", 0);
+ if (!prop)
+ return -ENOMEM;
+ private->cabc_lut_property = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CABC_STAGE_UP", 0, 512);
+ if (!prop)
+ return -ENOMEM;
+ private->cabc_stage_up_property = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CABC_STAGE_DOWN", 0, 255);
+ if (!prop)
+ return -ENOMEM;
+ private->cabc_stage_down_property = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CABC_GLOBAL_DN", 0, 255);
+ if (!prop)
+ return -ENOMEM;
+ private->cabc_global_dn_property = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CABC_CALC_PIXEL_NUM", 0, 1000);
+ if (!prop)
+ return -ENOMEM;
+ private->cabc_calc_pixel_num_property = prop;
+
+ return 0;
+}
+
static int rockchip_drm_bind(struct device *dev)
{
struct drm_device *drm_dev;
drm_dev->dev_private = private;
+ private->hdmi_pll.pll = devm_clk_get(dev, "hdmi-tmds-pll");
+ if (PTR_ERR(private->hdmi_pll.pll) == -ENOENT) {
+ private->hdmi_pll.pll = NULL;
+ } else if (PTR_ERR(private->hdmi_pll.pll) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_free;
+ } else if (IS_ERR(private->hdmi_pll.pll)) {
+ dev_err(dev, "failed to get hdmi-tmds-pll\n");
+ ret = PTR_ERR(private->hdmi_pll.pll);
+ goto err_free;
+ }
+
+ private->default_pll.pll = devm_clk_get(dev, "default-vop-pll");
+ if (PTR_ERR(private->default_pll.pll) == -ENOENT) {
+ private->default_pll.pll = NULL;
+ } else if (PTR_ERR(private->default_pll.pll) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto err_free;
+ } else if (IS_ERR(private->default_pll.pll)) {
+ dev_err(dev, "failed to get default vop pll\n");
+ ret = PTR_ERR(private->default_pll.pll);
+ goto err_free;
+ }
+
#ifdef CONFIG_DRM_DMA_SYNC
private->cpu_fence_context = fence_context_alloc(1);
atomic_set(&private->cpu_fence_seqno, 0);
drm_mode_config_init(drm_dev);
rockchip_drm_mode_config_init(drm_dev);
+ rockchip_drm_create_properties(drm_dev);
ret = rockchip_drm_init_iommu(drm_dev);
if (ret)
.gem_prime_vmap = rockchip_gem_prime_vmap,
.gem_prime_vunmap = rockchip_gem_prime_vunmap,
.gem_prime_mmap = rockchip_gem_mmap_buf,
+ .gem_prime_begin_cpu_access = rockchip_gem_prime_begin_cpu_access,
+ .gem_prime_end_cpu_access = rockchip_gem_prime_end_cpu_access,
#ifdef CONFIG_DEBUG_FS
.debugfs_init = rockchip_drm_debugfs_init,
.debugfs_cleanup = rockchip_drm_debugfs_cleanup,
of_node_put(port);
}
+ port = of_parse_phandle(np, "backlight", 0);
+ if (port && of_device_is_available(port)) {
+ component_match_add(dev, &match, compare_of, port);
+ of_node_put(port);
+ }
+
return component_master_add_with_match(dev, &rockchip_drm_ops, match);
}