From 1ef0e98b2949eeb3917c0ffe70662f118983c39f Mon Sep 17 00:00:00 2001 From: lilijun Date: Fri, 18 Oct 2024 10:45:13 +0800 Subject: [PATCH 193/219] sync:drm support debugfs control virtual Changelogs: 1.Sync code from eic7702 2.Add debugfs to control virtual dev Signed-off-by: lilijun --- .../dts/eswin/eswin-win2030-die0-soc.dtsi | 12 +- arch/riscv/configs/eic7700_dbg_defconfig | 1 + arch/riscv/configs/eic7700_defconfig | 1 + arch/riscv/configs/win2030_defconfig | 1 + drivers/gpu/drm/eswin/es_dc.c | 51 +- drivers/gpu/drm/eswin/es_dc_mmu.c | 6 - drivers/gpu/drm/eswin/es_drv.c | 243 ++++--- drivers/gpu/drm/eswin/es_drv.h | 2 + drivers/gpu/drm/eswin/es_gem.c-dbg | 607 ++++++++++++++++++ drivers/gpu/drm/eswin/es_mipi_dsi.c | 12 +- drivers/gpu/drm/eswin/es_panel.c | 7 +- drivers/gpu/drm/eswin/es_virtual.c | 77 ++- drivers/gpu/drm/eswin/es_virtual.h | 1 + 13 files changed, 878 insertions(+), 143 deletions(-) create mode 100644 drivers/gpu/drm/eswin/es_gem.c-dbg diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi index 4a79fe6b0721..daf927d2b3df 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi @@ -1780,9 +1780,10 @@ d0_graphcard2: graphcard2 { compatible = "audio-graph-card"; }; - video_output: display-subsystem { + video_output: display-subsystem@0 { compatible = "eswin,display-subsystem"; ports = <&dc_out>; + numa-node-id = <0>; dma-noncoherent; }; @@ -1809,6 +1810,7 @@ dc: display_control@502c0000 { <&d0_reset VO_RST_CTRL SW_VO_DC_PRSTN>; reset-names = "vo_arst", "vo_prst", "dc_arst", "dc_prst"; dma-noncoherent; + numa-node-id = <0>; dc_out: port { #address-cells = <1>; @@ -1831,9 +1833,10 @@ dc_out_hdmi: endpoint@2 { }; }; - virtual_display: es_wb { + virtual_display: es_wb@0 { compatible = "eswin,virtual_display"; bpp = /bits/ 8 <8>; + numa-node-id = <0>; port { vd_input: endpoint { @@ -1842,8 +1845,9 @@ vd_input: endpoint { }; }; - dsi_output: dsi-output { + dsi_output: dsi-output@0 { compatible = "eswin,dsi-encoder"; + numa-node-id = <0>; status = "disabled"; }; @@ -1856,6 +1860,8 @@ dsi_controller: mipi_dsi@50270000 { clock-names = "pclk"; resets = <&d0_reset VO_PHYRST_CTRL SW_VO_MIPI_PRSTN>; reset-names ="phyrstn"; + numa-node-id = <0>; + /* phys = <&dphy>; phy-names = "dphy"; diff --git a/arch/riscv/configs/eic7700_dbg_defconfig b/arch/riscv/configs/eic7700_dbg_defconfig index ed5d3e6ea9e3..069888c4aeed 100644 --- a/arch/riscv/configs/eic7700_dbg_defconfig +++ b/arch/riscv/configs/eic7700_dbg_defconfig @@ -626,6 +626,7 @@ CONFIG_DRM_SIMPLEDRM=m CONFIG_DRM_ESWIN=y CONFIG_ESWIN_MMU=y CONFIG_ESWIN_DW_HDMI=y +CONFIG_ESWIN_VIRTUAL_DISPLAY=y CONFIG_DW_HDMI_I2S_AUDIO=y CONFIG_DW_HDMI_CEC=y CONFIG_DRM_IMG_VOLCANIC=m diff --git a/arch/riscv/configs/eic7700_defconfig b/arch/riscv/configs/eic7700_defconfig index dcb4a252da20..ce5fb86d2d9b 100644 --- a/arch/riscv/configs/eic7700_defconfig +++ b/arch/riscv/configs/eic7700_defconfig @@ -641,6 +641,7 @@ CONFIG_DRM_SIMPLEDRM=m CONFIG_DRM_ESWIN=y CONFIG_ESWIN_MMU=y CONFIG_ESWIN_DW_HDMI=y +CONFIG_ESWIN_VIRTUAL_DISPLAY=y CONFIG_DW_HDMI_I2S_AUDIO=y CONFIG_DW_HDMI_CEC=y CONFIG_DRM_IMG_VOLCANIC=m diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig index f0d832fcd112..cc2484e64c2c 100644 --- a/arch/riscv/configs/win2030_defconfig +++ b/arch/riscv/configs/win2030_defconfig @@ -635,6 +635,7 @@ CONFIG_DRM_SIMPLEDRM=m CONFIG_DRM_ESWIN=y CONFIG_ESWIN_MMU=y CONFIG_ESWIN_DW_HDMI=y +CONFIG_ESWIN_VIRTUAL_DISPLAY=y CONFIG_DW_HDMI_I2S_AUDIO=y CONFIG_DW_HDMI_CEC=y CONFIG_DRM_IMG_VOLCANIC=m diff --git a/drivers/gpu/drm/eswin/es_dc.c b/drivers/gpu/drm/eswin/es_dc.c index ac43c604a2dc..f63bd798320e 100644 --- a/drivers/gpu/drm/eswin/es_dc.c +++ b/drivers/gpu/drm/eswin/es_dc.c @@ -636,26 +636,27 @@ static void update_overlay_plane(struct es_dc *dc, struct es_plane *plane) dc_hw_set_blend(&dc->hw, &blend); } -static void update_cursor_size(struct drm_plane_state *state, struct dc_hw_cursor *cursor) +static void update_cursor_size(struct drm_plane_state *state, + struct dc_hw_cursor *cursor) { u8 size_type; switch (state->crtc_w) { - case 32: - size_type = CURSOR_SIZE_32X32; - break; - case 64: - size_type = CURSOR_SIZE_64X64; - break; - case 128: - size_type = CURSOR_SIZE_128X128; - break; - case 256: - size_type = CURSOR_SIZE_256X256; - break; - default: - size_type = CURSOR_SIZE_32X32; - break; + case 32: + size_type = CURSOR_SIZE_32X32; + break; + case 64: + size_type = CURSOR_SIZE_64X64; + break; + case 128: + size_type = CURSOR_SIZE_128X128; + break; + case 256: + size_type = CURSOR_SIZE_256X256; + break; + default: + size_type = CURSOR_SIZE_32X32; + break; } cursor->size = size_type; @@ -873,12 +874,14 @@ static int dc_bind(struct device *dev, struct device *master, void *data) } #ifdef CONFIG_ESWIN_MMU - ret = dc_mmu_construct(priv->dma_dev, &priv->mmu); - if (ret) { - dev_err(dev, "failed to construct DC MMU\n"); - goto err_clean_dc; + if (priv->mmu_constructed == false) { + ret = dc_mmu_construct(priv->dma_dev, &priv->mmu); + if (ret) { + dev_err(dev, "failed to construct DC MMU\n"); + goto err_clean_dc; + } + priv->mmu_constructed = true; } - ret = dc_hw_mmu_init(&dc->hw, priv->mmu); if (ret) { dev_err(dev, "failed to init DC MMU\n"); @@ -950,8 +953,8 @@ static int dc_bind(struct device *dev, struct device *master, void *data) return 0; err_cleanup_planes: - list_for_each_entry_safe (drm_plane, tmp, - &drm_dev->mode_config.plane_list, head) + list_for_each_entry_safe(drm_plane, tmp, + &drm_dev->mode_config.plane_list, head) if (drm_plane->possible_crtcs == drm_crtc_mask(&crtc->base)) es_plane_destory(drm_plane); @@ -981,7 +984,7 @@ static void vo_qos_cfg(void) { void __iomem *qos; - #define VO_QOS_CSR 0x50281050UL +#define VO_QOS_CSR 0x50281050UL qos = ioremap(VO_QOS_CSR, 8); if (!qos) { printk("qos ioremap fail---------------\n"); diff --git a/drivers/gpu/drm/eswin/es_dc_mmu.c b/drivers/gpu/drm/eswin/es_dc_mmu.c index 80cbeb421740..260f549aeff7 100644 --- a/drivers/gpu/drm/eswin/es_dc_mmu.c +++ b/drivers/gpu/drm/eswin/es_dc_mmu.c @@ -18,8 +18,6 @@ #include "es_dc_mmu.h" -static bool mmu_construct = false; - int _allocate_memory(u32 bytes, void **memory) { void *mem = NULL; @@ -298,9 +296,6 @@ int dc_mmu_construct(struct device *dev, dc_mmu_pt *mmu) u32 size = 0; int ret = 0; - if (mmu_construct) - return 0; - mem = kzalloc(sizeof(dc_mmu), GFP_KERNEL); if (!mem) return -ENOMEM; @@ -351,7 +346,6 @@ int dc_mmu_construct(struct device *dev, dc_mmu_pt *mmu) memset(mmu_t->safe_page_logical, 0, size); *mmu = mmu_t; - mmu_construct = true; return 0; } diff --git a/drivers/gpu/drm/eswin/es_drv.c b/drivers/gpu/drm/eswin/es_drv.c index 2596e8e492a3..a589b9cc9ae5 100644 --- a/drivers/gpu/drm/eswin/es_drv.c +++ b/drivers/gpu/drm/eswin/es_drv.c @@ -65,7 +65,7 @@ static int es_debugfs_planes_show(struct seq_file *s, void *data) struct drm_device *dev = node->minor->dev; struct drm_plane *plane = NULL; - list_for_each_entry (plane, &dev->mode_config.plane_list, head) { + list_for_each_entry(plane, &dev->mode_config.plane_list, head) { struct drm_plane_state *state = plane->state; struct es_plane_state *plane_state = to_es_plane_state(state); @@ -101,8 +101,8 @@ static void es_debugfs_init(struct drm_minor *minor) #endif static struct drm_driver es_drm_driver = { - .driver_features = - DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM | DRIVER_SYNCOBJ, + .driver_features = DRIVER_MODESET | DRIVER_ATOMIC | DRIVER_GEM | + DRIVER_SYNCOBJ, .lastclose = drm_fb_helper_lastclose, .gem_prime_import = es_gem_prime_import, .gem_prime_import_sg_table = es_gem_prime_import_sg_table, @@ -226,13 +226,12 @@ static int es_drm_bind(struct device *dev) { struct drm_device *drm_dev; struct es_drm_private *priv; - int ret; + int ret, id; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) static u64 dma_mask = DMA_BIT_MASK(40); #else static u64 dma_mask = DMA_40BIT_MASK; #endif - drm_dev = drm_dev_alloc(&es_drm_driver, dev); if (IS_ERR(drm_dev)) return PTR_ERR(drm_dev); @@ -280,6 +279,20 @@ static int es_drm_bind(struct device *dev) drm_fbdev_generic_setup(drm_dev, 32); + ret = of_property_read_u32(dev->of_node, "numa-node-id", &id); + if (ret) { + DRM_DEV_ERROR(dev, "Failed to read index property, ret = %d\n", + ret); + return ret; + } + DRM_INFO("drm dev is on die%d\n", id); + priv->die_id = id; + priv->mmu_constructed = false; + + if (drm_dev->unique) { + sprintf(drm_dev->unique, "%d", id); + } + DRM_INFO("drm_dev name:%s\n", drm_dev->unique); return 0; err_helper: @@ -323,88 +336,38 @@ static const struct component_master_ops es_drm_ops = { .unbind = es_drm_unbind, }; -static struct platform_driver *drm_sub_drivers[] = { - /* put display control driver at start */ - &dc_platform_driver, - -/* connector */ - -/* bridge */ -#if 1 -#ifdef CONFIG_ESWIN_DW_HDMI - &dw_hdmi_eswin_pltfm_driver, -#endif -#ifdef CONFIG_DW_HDMI_I2S_AUDIO - &snd_dw_hdmi_driver, -#endif - -#ifdef CONFIG_DW_HDMI_CEC - &dw_hdmi_cec_driver, -#endif - -#ifdef CONFIG_DW_HDMI_HDCP - &dw_hdmi_hdcp_driver, -#endif -#endif - -#ifdef CONFIG_ESWIN_VIRTUAL_DISPLAY - &virtual_display_platform_driver, -#endif - -#ifdef CONFIG_ESWIN_MIPI_DSI - &es_mipi_dsi_driver, -#endif - -}; -#define NUM_DRM_DRIVERS \ - (sizeof(drm_sub_drivers) / sizeof(struct platform_driver *)) - -static int compare_dev(struct device *dev, void *data) +static int compare_of(struct device *dev, void *data) { - return dev == (struct device *)data; + // DRM_INFO("Comparing of node %pOF with %pOF\n", dev->of_node, data); + return dev->of_node == data; } -static struct component_match *es_drm_match_add(struct device *dev) +static int es_drm_of_component_probe(struct device *dev, + int (*compare_of)(struct device *, void *), + const struct component_master_ops *m_ops) { + struct device_node *ep, *port, *remote; struct component_match *match = NULL; int i; - - for (i = 0; i < NUM_DRM_DRIVERS; ++i) { - struct platform_driver *drv = drm_sub_drivers[i]; - struct device *p = NULL, *d; - - while ((d = platform_find_device_by_driver(p, &drv->driver))) { - put_device(p); - - component_match_add(dev, &match, compare_dev, d); - p = d; - } - put_device(p); - } - - return match ?: ERR_PTR(-ENODEV); -} - -static int es_drm_platform_of_probe(struct device *dev) -{ - struct device_node *np = dev->of_node; - struct device_node *port; bool found = false; - int i; + bool matched = false; - if (!np) - return -ENODEV; + if (!dev->of_node) + return -EINVAL; + /* + * Bind the crtc's ports first, so that drm_of_find_possible_crtcs() + * called from encoder's .bind callbacks works as expected + */ for (i = 0;; i++) { struct device_node *iommu; - - port = of_parse_phandle(np, "ports", i); + port = of_parse_phandle(dev->of_node, "ports", i); if (!port) break; - if (!of_device_is_available(port->parent)) { - of_node_put(port); - continue; + if (of_device_is_available(port->parent)) { + drm_of_component_match_add(dev, &match, compare_of, + port->parent); } iommu = of_parse_phandle(port->parent, "iommus", 0); @@ -422,34 +385,85 @@ static int es_drm_platform_of_probe(struct device *dev) of_node_put(port); } + if (!found) { + DRM_DEV_ERROR(dev, "No available DC found.\n"); + return -ENODEV; + } + if (i == 0) { - DRM_DEV_ERROR(dev, "missing 'ports' property\n"); + dev_err(dev, "missing 'ports' property\n"); return -ENODEV; } - if (!found) { - DRM_DEV_ERROR(dev, "No available DC found.\n"); + if (!match) { + dev_err(dev, "no available port\n"); return -ENODEV; } - return 0; + /* + * For bound crtcs, bind the encoders attached to their remote endpoint + */ + for (i = 0;; i++) { + port = of_parse_phandle(dev->of_node, "ports", i); + if (!port) + break; + + if (!of_device_is_available(port->parent)) { + of_node_put(port); + continue; + } + + for_each_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote || !of_device_is_available(remote)) { + of_node_put(remote); + continue; + } else if (!of_device_is_available(remote->parent)) { + dev_warn( + dev, + "parent device of %pOF is not available\n", + remote); + of_node_put(remote); + continue; + } + +#ifdef CONFIG_ESWIN_DW_HDMI + if (!strcmp(remote->name, "hdmi")) { + matched = true; + } +#endif + +#ifdef CONFIG_ESWIN_VIRTUAL_DISPLAY + if (!strcmp(remote->name, "es_wb")) { + matched = true; + } +#endif + +#ifdef CONFIG_ESWIN_MIPI_DSI + if (!strcmp(remote->name, "mipi_dsi")) { + matched = true; + } +#endif + if (matched == true) { + drm_of_component_match_add(dev, &match, + compare_of, remote); + matched = false; + dev_dbg(dev, "matched: %pOF, remote->name:%s\n", + remote, remote->name); + } + + of_node_put(remote); + } + of_node_put(port); + } + return component_master_add_with_match(dev, m_ops, match); } static int es_drm_platform_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct component_match *match; - int ret; - - ret = es_drm_platform_of_probe(dev); - if (ret) - return ret; - - match = es_drm_match_add(dev); - if (IS_ERR(match)) - return PTR_ERR(match); + DRM_INFO("drm platform probe enter\n"); - return component_master_add_with_match(dev, &es_drm_ops, match); + return es_drm_of_component_probe(&pdev->dev, compare_of, &es_drm_ops); } static int es_drm_platform_remove(struct platform_device *pdev) @@ -499,25 +513,52 @@ static struct platform_driver es_drm_platform_driver = { }, }; -static int __init es_drm_init(void) -{ - int ret; +static struct platform_driver *const drivers[] = { + &es_drm_platform_driver, + /* put display control driver at start */ + &dc_platform_driver, - ret = platform_register_drivers(drm_sub_drivers, NUM_DRM_DRIVERS); - if (ret) - return ret; +/* connector */ - ret = platform_driver_register(&es_drm_platform_driver); - if (ret) - platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS); +/* bridge */ +#if 1 +#ifdef CONFIG_ESWIN_DW_HDMI + &dw_hdmi_eswin_pltfm_driver, +#endif +#ifdef CONFIG_DW_HDMI_I2S_AUDIO + &snd_dw_hdmi_driver, +#endif - return ret; +#ifdef CONFIG_DW_HDMI_CEC + &dw_hdmi_cec_driver, +#endif + +#ifdef CONFIG_DW_HDMI_HDCP + &dw_hdmi_hdcp_driver, +#endif +#endif + +#ifdef CONFIG_ESWIN_VIRTUAL_DISPLAY + &virtual_display_platform_driver, +#endif + +#ifdef CONFIG_ESWIN_MIPI_DSI + &es_mipi_dsi_driver, +#endif +}; + +static int __init es_drm_init(void) +{ + DRM_INFO("drm init enter\n"); + + return platform_register_drivers(drivers, ARRAY_SIZE(drivers)); } static void __exit es_drm_fini(void) { - platform_driver_unregister(&es_drm_platform_driver); - platform_unregister_drivers(drm_sub_drivers, NUM_DRM_DRIVERS); + DRM_INFO("drm exit enter\n"); + + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); } module_init(es_drm_init); diff --git a/drivers/gpu/drm/eswin/es_drv.h b/drivers/gpu/drm/eswin/es_drv.h index 85465f559de0..863e4b1da74a 100644 --- a/drivers/gpu/drm/eswin/es_drv.h +++ b/drivers/gpu/drm/eswin/es_drv.h @@ -43,7 +43,9 @@ struct es_drm_private { #ifdef CONFIG_ESWIN_MMU dc_mmu *mmu; + bool mmu_constructed; #endif + unsigned int die_id; unsigned int pitch_alignment; }; diff --git a/drivers/gpu/drm/eswin/es_gem.c-dbg b/drivers/gpu/drm/eswin/es_gem.c-dbg new file mode 100644 index 000000000000..641fde6cc44e --- /dev/null +++ b/drivers/gpu/drm/eswin/es_gem.c-dbg @@ -0,0 +1,607 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Eswin Holdings Co., Ltd. + */ + +#include +#include + +#include "es_drv.h" +#include "es_gem.h" + +MODULE_IMPORT_NS(DMA_BUF); + +static const struct drm_gem_object_funcs es_gem_default_funcs; + +static void nonseq_free(struct page **pages, unsigned int nr_page) +{ + u32 i; + + if (!pages) + return; + + for (i = 0; i < nr_page; i++) + __free_page(pages[i]); +} + +#ifdef CONFIG_ESWIN_MMU +static int get_pages(unsigned int nr_page, struct es_gem_object *es_obj) +{ + struct page *pages; + u32 i, num_page, page_count = 0; + int order = 0; + gfp_t gfp = GFP_KERNEL; + + if (!es_obj->pages) + return -EINVAL; + + gfp &= ~__GFP_HIGHMEM; + gfp |= __GFP_DMA32; + + num_page = nr_page; + + do { + pages = NULL; + order = get_order(num_page * PAGE_SIZE); + num_page = 1 << order; + + if ((num_page + page_count > nr_page) || (order >= MAX_ORDER)) { + num_page = num_page >> 1; + continue; + } + + pages = alloc_pages(gfp, order); + if (!pages) { + if (num_page == 1) { + nonseq_free(es_obj->pages, page_count); + return -ENOMEM; + } + + num_page = num_page >> 1; + } else { + for (i = 0; i < num_page; i++) { + es_obj->pages[page_count + i] = &pages[i]; + SetPageReserved(es_obj->pages[page_count + i]); + } + + page_count += num_page; + num_page = nr_page - page_count; + } + + } while (page_count < nr_page); + + es_obj->get_pages = true; + + return 0; +} +#endif + +static void put_pages(unsigned int nr_page, struct es_gem_object *es_obj) +{ + u32 i; + + for (i = 0; i < nr_page; i++) + ClearPageReserved(es_obj->pages[i]); + + nonseq_free(es_obj->pages, nr_page); + + return; +} + +static int es_gem_alloc_buf(struct es_gem_object *es_obj) +{ + struct drm_device *dev = es_obj->base.dev; + unsigned int nr_pages; + struct sg_table sgt; + int ret = -ENOMEM; +#ifdef CONFIG_ESWIN_MMU + struct es_drm_private *priv = dev->dev_private; +#endif + + if (es_obj->dma_addr) { + DRM_DEV_DEBUG_KMS(dev->dev, "already allocated.\n"); + return 0; + } + + es_obj->dma_attrs = DMA_ATTR_WRITE_COMBINE; + + if (!is_iommu_enabled(dev)) + es_obj->dma_attrs |= DMA_ATTR_FORCE_CONTIGUOUS; + + nr_pages = es_obj->size >> PAGE_SHIFT; + + es_obj->pages = kvmalloc_array(nr_pages, sizeof(struct page *), + GFP_KERNEL | __GFP_ZERO); + if (!es_obj->pages) { + DRM_DEV_ERROR(dev->dev, "failed to allocate pages.\n"); + return -ENOMEM; + } + + es_obj->cookie = dma_alloc_attrs(to_dma_dev(dev), es_obj->size, + &es_obj->dma_addr, GFP_KERNEL, + es_obj->dma_attrs); + printk("lijun cma_phy:0x%llx, size:%ld dev name %s\n", es_obj->dma_addr,dev_name(dev->dev)); + if (!es_obj->cookie) { +#ifdef CONFIG_ESWIN_MMU + ret = get_pages(nr_pages, es_obj); + if (ret) { + DRM_DEV_ERROR(dev->dev, "fail to allocate buffer.\n"); + goto err_free; + } +#else + DRM_DEV_ERROR(dev->dev, "failed to allocate buffer.\n"); + goto err_free; +#endif + } + +#ifdef CONFIG_ESWIN_MMU + /* MMU map*/ + if (!priv->mmu) { + DRM_DEV_ERROR(dev->dev, "invalid mmu.\n"); + ret = -EINVAL; + goto err_mem_free; + } + + if (!es_obj->get_pages) + ret = dc_mmu_map_memory(priv->mmu, (u64)es_obj->dma_addr, + nr_pages, &es_obj->iova, true); + else + ret = dc_mmu_map_memory(priv->mmu, (u64)es_obj->pages, nr_pages, + &es_obj->iova, false); + + if (ret) { + DRM_DEV_ERROR(dev->dev, "failed to do mmu map.\n"); + goto err_mem_free; + } +#else + es_obj->iova = es_obj->dma_addr; +#endif + + if (!es_obj->get_pages) { + ret = dma_get_sgtable_attrs(to_dma_dev(dev), &sgt, + es_obj->cookie, es_obj->dma_addr, + es_obj->size, es_obj->dma_attrs); + if (ret < 0) { + DRM_DEV_ERROR(dev->dev, "failed to get sgtable.\n"); + goto err_mem_free; + } + + if (drm_prime_sg_to_page_array(&sgt, es_obj->pages, nr_pages)) { + DRM_DEV_ERROR(dev->dev, "invalid sgtable.\n"); + ret = -EINVAL; + goto err_sgt_free; + } + + sg_free_table(&sgt); + } + + return 0; + +err_sgt_free: + sg_free_table(&sgt); +err_mem_free: + if (!es_obj->get_pages) + dma_free_attrs(to_dma_dev(dev), es_obj->size, es_obj->cookie, + es_obj->dma_addr, es_obj->dma_attrs); + else + put_pages(nr_pages, es_obj); +err_free: + kvfree(es_obj->pages); + + return ret; +} + +static void es_gem_free_buf(struct es_gem_object *es_obj) +{ + struct drm_device *dev = es_obj->base.dev; +#ifdef CONFIG_ESWIN_MMU + struct es_drm_private *priv = dev->dev_private; + unsigned int nr_pages; +#endif + + if ((!es_obj->get_pages) && (!es_obj->dma_addr)) { + DRM_DEV_DEBUG_KMS(dev->dev, "dma_addr is invalid.\n"); + return; + } + +#ifdef CONFIG_ESWIN_MMU + if (!priv->mmu) { + DRM_DEV_ERROR(dev->dev, "invalid mmu.\n"); + return; + } + + if (!es_obj->sgt) { // dumb buffer release + nr_pages = es_obj->size >> PAGE_SHIFT; + if (es_obj->iova) { + dc_mmu_unmap_memory(priv->mmu, es_obj->iova, nr_pages); + } + } else { // prime buffer release + if (es_obj->iova_list) { + if (es_obj->iova_list->iova) { + dc_mmu_unmap_memory( + priv->mmu, es_obj->iova_list->iova, + es_obj->iova_list->nr_pages); + kfree(es_obj->iova_list); + } + } + } +#endif + + if (!es_obj->get_pages) { + dma_free_attrs(to_dma_dev(dev), es_obj->size, es_obj->cookie, + (dma_addr_t)es_obj->dma_addr, es_obj->dma_attrs); + } else { + if (!es_obj->dma_addr) { + DRM_DEV_ERROR(dev->dev, "No dma addr allocated, no need to free\n"); + return; + } + put_pages(es_obj->size >> PAGE_SHIFT, es_obj); + } + + kvfree(es_obj->pages); +} + +static void es_gem_free_object(struct drm_gem_object *obj) +{ + struct es_gem_object *es_obj = to_es_gem_object(obj); + +#ifdef CONFIG_ESWIN_MMU + if (es_obj) + es_gem_free_buf(es_obj); +#endif + if (obj->import_attach) { + drm_prime_gem_destroy(obj, es_obj->sgt); + } + + drm_gem_object_release(obj); + + kfree(es_obj); +} + +static struct es_gem_object *es_gem_alloc_object(struct drm_device *dev, + size_t size) +{ + struct es_gem_object *es_obj; + struct drm_gem_object *obj; + int ret; + + es_obj = kzalloc(sizeof(*es_obj), GFP_KERNEL); + if (!es_obj) + return ERR_PTR(-ENOMEM); + + es_obj->size = size; + obj = &es_obj->base; + + ret = drm_gem_object_init(dev, obj, size); + if (ret) + goto err_free; + + es_obj->base.funcs = &es_gem_default_funcs; + + ret = drm_gem_create_mmap_offset(obj); + if (ret) { + drm_gem_object_release(obj); + goto err_free; + } + + return es_obj; + +err_free: + kfree(es_obj); + return ERR_PTR(ret); +} + +struct es_gem_object *es_gem_create_object(struct drm_device *dev, size_t size) +{ + struct es_gem_object *es_obj; + int ret; + + size = PAGE_ALIGN(size); + + es_obj = es_gem_alloc_object(dev, size); + if (IS_ERR(es_obj)) + return es_obj; + + ret = es_gem_alloc_buf(es_obj); + if (ret) { + drm_gem_object_release(&es_obj->base); + kfree(es_obj); + return ERR_PTR(ret); + } + + return es_obj; +} + +static struct es_gem_object *es_gem_create_with_handle(struct drm_device *dev, + struct drm_file *file, + size_t size, + unsigned int *handle) +{ + struct es_gem_object *es_obj; + struct drm_gem_object *obj; + int ret; + + es_obj = es_gem_create_object(dev, size); + if (IS_ERR(es_obj)) + return es_obj; + + obj = &es_obj->base; + + ret = drm_gem_handle_create(file, obj, handle); + drm_gem_object_put(obj); + if (ret) { + pr_err("Drm GEM handle create failed\n"); + return ERR_PTR(ret); + } + + return es_obj; +} + +static int es_gem_mmap_obj(struct drm_gem_object *obj, + struct vm_area_struct *vma) +{ + struct es_gem_object *es_obj = to_es_gem_object(obj); + struct drm_device *drm_dev = es_obj->base.dev; + unsigned long vm_size; + int ret = 0; + + vm_size = vma->vm_end - vma->vm_start; + if (vm_size > es_obj->size) + return -EINVAL; + + vma->vm_pgoff = 0; + + if (!es_obj->get_pages) { + vm_flags_clear(vma, VM_PFNMAP); + + ret = dma_mmap_attrs(to_dma_dev(drm_dev), vma, es_obj->cookie, + es_obj->dma_addr, es_obj->size, + es_obj->dma_attrs); + } else { + u32 i, nr_pages, pfn = 0U; + unsigned long start; + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + vm_flags_set(vma, VM_IO | VM_DONTCOPY | VM_DONTEXPAND | VM_DONTDUMP); + start = vma->vm_start; + vm_size = PAGE_ALIGN(vm_size); + nr_pages = vm_size >> PAGE_SHIFT; + + for (i = 0; i < nr_pages; i++) { + pfn = page_to_pfn(es_obj->pages[i]); + + ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, + vma->vm_page_prot); + if (ret < 0) + break; + + start += PAGE_SIZE; + } + } + + if (ret) + drm_gem_vm_close(vma); + + return ret; +} + +struct sg_table *es_gem_prime_get_sg_table(struct drm_gem_object *obj) +{ + struct es_gem_object *es_obj = to_es_gem_object(obj); + + return drm_prime_pages_to_sg(obj->dev, es_obj->pages, + es_obj->size >> PAGE_SHIFT); +} + +static int es_gem_prime_vmap(struct drm_gem_object *obj, + struct iosys_map *map) +{ + struct es_gem_object *es_obj = to_es_gem_object(obj); + + void * vaddr = es_obj->dma_attrs & DMA_ATTR_NO_KERNEL_MAPPING ? + page_address(es_obj->cookie) : es_obj->cookie; + + iosys_map_set_vaddr(map, vaddr); + + return 0; +} + +static void es_gem_prime_vunmap(struct drm_gem_object *obj, + struct iosys_map *map) +{ + /* Nothing to do */ +} + +static const struct vm_operations_struct es_vm_ops = { + .open = drm_gem_vm_open, + .close = drm_gem_vm_close, +}; + +static const struct drm_gem_object_funcs es_gem_default_funcs = { + .free = es_gem_free_object, + .get_sg_table = es_gem_prime_get_sg_table, + .vmap = es_gem_prime_vmap, + .vunmap = es_gem_prime_vunmap, + .vm_ops = &es_vm_ops, +}; + +int es_gem_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct es_drm_private *priv = dev->dev_private; + struct es_gem_object *es_obj; + unsigned int pitch = args->width * DIV_ROUND_UP(args->bpp, 8); + + args->pitch = ALIGN(pitch, priv->pitch_alignment); + args->size = PAGE_ALIGN(args->pitch * args->height); + + es_obj = + es_gem_create_with_handle(dev, file, args->size, &args->handle); + return PTR_ERR_OR_ZERO(es_obj); +} + +struct drm_gem_object *es_gem_prime_import(struct drm_device *dev, + struct dma_buf *dma_buf) +{ + return drm_gem_prime_import_dev(dev, dma_buf, to_dma_dev(dev)); +} + +struct drm_gem_object * +es_gem_prime_import_sg_table(struct drm_device *dev, + struct dma_buf_attachment *attach, + struct sg_table *sgt) +{ + struct es_gem_object *es_obj; + int npages; + int ret; + struct scatterlist *s = NULL; + u32 i = 0; + dma_addr_t expected; + size_t size = attach->dmabuf->size; +#ifdef CONFIG_ESWIN_MMU + u32 iova, j; + struct scatterlist **splist; + struct es_drm_private *priv = dev->dev_private; + + if (!priv->mmu) { + DRM_ERROR("invalid mmu.\n"); + ret = -EINVAL; + return ERR_PTR(ret); + } +#endif + + size = PAGE_ALIGN(size); + + es_obj = es_gem_alloc_object(dev, size); + if (IS_ERR(es_obj)) + return ERR_CAST(es_obj); + + npages = es_obj->size >> PAGE_SHIFT; + es_obj->pages = + kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); + if (!es_obj->pages) { + ret = -ENOMEM; + goto err_gemalloc; + } + + ret = drm_prime_sg_to_page_array(sgt, es_obj->pages, npages); + if (ret) + goto err_free_page; + + expected = sg_dma_address(sgt->sgl); + printk("lijun : dma sgl dma:0x%llx, phy:0x%llx\n", expected); +#ifdef CONFIG_ESWIN_MMU + splist = (struct scatterlist **)kzalloc(sizeof(s) * sgt->nents, + GFP_KERNEL); + if (!splist) { + DRM_ERROR("Allocate splist failed"); + ret = -ENOMEM; + goto err_free_page; + } + + es_obj->iova_list = + (iova_info_t *)kzalloc(sizeof(iova_info_t), GFP_KERNEL); + if (!es_obj->iova_list) { + DRM_ERROR("Allocate splist failed"); + ret = -ENOMEM; + goto err_sp; + } + + for_each_sg (sgt->sgl, s, sgt->nents, i) { + splist[i] = s; + } + i = 0; + es_obj->nr_iova = sgt->nents; + + for (j = sgt->nents; j > 0; j--) { + s = splist[j - 1]; +#else + for_each_sg (sgt->sgl, s, sgt->nents, i) { +#endif + if (sg_dma_address(s) != expected) { +#ifndef CONFIG_ESWIN_MMU + DRM_ERROR("sg_table is not contiguous"); + ret = -EINVAL; + goto err; +#endif + } + + if (sg_dma_len(s) & (PAGE_SIZE - 1)) { + ret = -EINVAL; + goto err; + } + +#ifdef CONFIG_ESWIN_MMU + iova = 0; + + if (j == 1) { + ret = dc_mmu_map_memory(priv->mmu, (u64)es_obj->pages, + npages, &iova, false); + if (ret) { + DRM_ERROR("failed to do mmu map.\n"); + goto err; + } + es_obj->iova_list->iova = iova; + es_obj->iova_list->nr_pages = npages; + } + + if (i == 0) + es_obj->iova = iova; +#else + if (i == 0) + es_obj->iova = sg_dma_address(s); +#endif + + expected = sg_dma_address(s) + sg_dma_len(s); + } + + es_obj->dma_addr = sg_dma_address(sgt->sgl); + + es_obj->sgt = sgt; +#ifdef CONFIG_ESWIN_MMU + kfree(splist); +#endif + + return &es_obj->base; + +#ifdef CONFIG_ESWIN_MMU +err: + kfree(es_obj->iova_list); +err_sp: + kfree(splist); +#endif +err_free_page: + kvfree(es_obj->pages); +err_gemalloc: + es_gem_free_object(&es_obj->base); + + return ERR_PTR(ret); +} + +int es_gem_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) +{ + int ret = 0; + + ret = drm_gem_mmap_obj(obj, obj->size, vma); + if (ret < 0) + return ret; + + return es_gem_mmap_obj(obj, vma); +} + +int es_gem_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_gem_object *obj; + int ret; + + ret = drm_gem_mmap(filp, vma); + if (ret) + return ret; + + obj = vma->vm_private_data; + + if (obj->import_attach) + return dma_buf_mmap(obj->dma_buf, vma, 0); + + return es_gem_mmap_obj(obj, vma); +} diff --git a/drivers/gpu/drm/eswin/es_mipi_dsi.c b/drivers/gpu/drm/eswin/es_mipi_dsi.c index 9f8d4c4a25b8..a083eebdea4d 100644 --- a/drivers/gpu/drm/eswin/es_mipi_dsi.c +++ b/drivers/gpu/drm/eswin/es_mipi_dsi.c @@ -81,6 +81,8 @@ #define HSTX_TO_CNT(p) (((p) & 0xffff) << 16) #define LPRX_TO_CNT(p) ((p) & 0xffff) +static bool panel_driver_registed = false; + struct hstt { unsigned int maxfreq; struct dw_mipi_dsi_dphy_timing timing; @@ -647,7 +649,10 @@ static const struct component_ops es_mipi_dsi_ops = { static int es_mipi_dsi_probe(struct platform_device *pdev) { - mipi_dsi_driver_register(&es_panel_driver); + if(panel_driver_registed == false) { + mipi_dsi_driver_register(&es_panel_driver); + panel_driver_registed = true; + } return component_add(&pdev->dev, &es_mipi_dsi_ops); } @@ -655,7 +660,10 @@ static int es_mipi_dsi_probe(struct platform_device *pdev) static int es_mipi_dsi_remove(struct platform_device *pdev) { DRM_INFO("mipi dsi remove\n"); - mipi_dsi_driver_unregister(&es_panel_driver); + if(panel_driver_registed == true) { + panel_driver_registed = false; + mipi_dsi_driver_unregister(&es_panel_driver); + } component_del(&pdev->dev, &es_mipi_dsi_ops); return 0; diff --git a/drivers/gpu/drm/eswin/es_panel.c b/drivers/gpu/drm/eswin/es_panel.c index 7342ab287c70..45424570364c 100644 --- a/drivers/gpu/drm/eswin/es_panel.c +++ b/drivers/gpu/drm/eswin/es_panel.c @@ -834,7 +834,6 @@ int es_panel_probe(struct mipi_dsi_device *dsi) int ret; struct device_node *dsi_node, *remote_node = NULL, *endpoint = NULL; int val; - // for print pr_dev = dev; dev_info(pr_dev, "[%s] Enter\n", __func__); @@ -886,6 +885,7 @@ int es_panel_probe(struct mipi_dsi_device *dsi) PTR_ERR(ctx->gpio_reset)); return PTR_ERR(ctx->gpio_reset); } + msleep(50); gpiod_set_value(ctx->gpio_reset, 1); @@ -904,11 +904,12 @@ int es_panel_probe(struct mipi_dsi_device *dsi) if (ret < 0) drm_panel_remove(&ctx->panel); - es_panel_chrdev_create(ctx); + // es_panel_chrdev_create(ctx); INIT_LIST_HEAD(&ctx->init_cmd_list); ctx->init_cmd_writted = 0; memset(&ctx->enable_cmd_buf, 0, sizeof(user_cmd_buffer_t)); memset(&ctx->disable_cmd_buf, 0, sizeof(user_cmd_buffer_t)); + dev_info(pr_dev, "[%s] Leave\n", __func__); return ret; } @@ -923,7 +924,7 @@ void es_panel_remove(struct mipi_dsi_device *dsi) devm_gpiod_put(ctx->dev, ctx->gpio_backlight0); devm_gpiod_put(ctx->dev, ctx->gpio_reset); - es_panel_chrdev_destroy(ctx); + // es_panel_chrdev_destroy(ctx); mipi_dsi_detach(dsi); drm_panel_remove(&ctx->panel); diff --git a/drivers/gpu/drm/eswin/es_virtual.c b/drivers/gpu/drm/eswin/es_virtual.c index 1d35ada1c0c0..eb546d32b4f3 100644 --- a/drivers/gpu/drm/eswin/es_virtual.c +++ b/drivers/gpu/drm/eswin/es_virtual.c @@ -1147,7 +1147,76 @@ static void vd_connector_destroy(struct drm_connector *connector) static enum drm_connector_status vd_connector_detect(struct drm_connector *connector, bool force) { - return connector_status_connected; + struct es_virtual_display *vd; + enum drm_connector_status status = connector_status_unknown; + + vd = to_virtual_display_with_connector(connector); + + if (vd->enable) { + status = connector_status_connected; + } else { + status = connector_status_disconnected; + } + return status; +} + +static ssize_t virtual_enable_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct es_virtual_display *vd = file->private_data; + char kbuf[16]; + int len; + + len = snprintf(kbuf, sizeof(kbuf), "%u\n", vd->enable); + + return simple_read_from_buffer(buf, count, ppos, kbuf, len); +} + +static ssize_t virtual_enable_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct es_virtual_display *vd = file->private_data; + char kbuf[16]; + unsigned long val; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(kbuf, buf, count)) + return -EFAULT; + + kbuf[count] = '\0'; + + if (kstrtoul(kbuf, 10, &val)) + return -EINVAL; + + vd->enable = val ? 1 : 0; + + return count; +} + +static const struct file_operations virtual_enable_debugfs_fops = { + .owner = THIS_MODULE, + .read = virtual_enable_read, + .write = virtual_enable_write, + .open = simple_open, + .llseek = default_llseek, +}; + +static void vd_connector_debugfs_init(struct drm_connector *connector, + struct dentry *root) +{ + struct es_virtual_display *vd; + + vd = to_virtual_display_with_connector(connector); + + if (!connector->debugfs_entry) { + DRM_WARN("The connector debugsf_entry invalid"); + } else { + debugfs_create_file("enable", 0444, connector->debugfs_entry, + vd, &virtual_enable_debugfs_fops); + } + DRM_INFO("Creat debugfs file for Vitual dev:%s", connector->name); } static const struct drm_connector_funcs vd_connector_funcs = { @@ -1157,8 +1226,8 @@ static const struct drm_connector_funcs vd_connector_funcs = { .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, .reset = drm_atomic_helper_connector_reset, + .debugfs_init = vd_connector_debugfs_init, }; - static int vd_bind(struct device *dev, struct device *master, void *data) { struct drm_device *drm_dev = data; @@ -1193,8 +1262,8 @@ static int vd_bind(struct device *dev, struct device *master, void *data) connector->interlace_allowed = false; connector->doublescan_allowed = false; connector->dpms = DRM_MODE_DPMS_OFF; - connector->polled = - DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; + connector->polled = DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT; ret = drm_connector_register(connector); if (ret) goto connector_reg_err; diff --git a/drivers/gpu/drm/eswin/es_virtual.h b/drivers/gpu/drm/eswin/es_virtual.h index 16371232d605..484d146ea178 100644 --- a/drivers/gpu/drm/eswin/es_virtual.h +++ b/drivers/gpu/drm/eswin/es_virtual.h @@ -7,6 +7,7 @@ #define __ES_VIRTUAL_H_ struct es_virtual_display { + u32 enable; struct drm_encoder encoder; struct drm_connector connector; struct device *dc; -- 2.47.0