add device tree support for mmp fb/controller the description at Documentation/devicetree/bindings/fb/mmp-disp.txt Signed-off-by: Zhou Zhu <zzhu3@xxxxxxxxxxx> --- Documentation/devicetree/bindings/fb/mmp-disp.txt | 71 ++++++++++++ drivers/video/mmp/fb/mmpfb.c | 71 ++++++++---- drivers/video/mmp/hw/mmp_ctrl.c | 120 ++++++++++++++++----- 3 files changed, 217 insertions(+), 45 deletions(-) create mode 100644 Documentation/devicetree/bindings/fb/mmp-disp.txt diff --git a/Documentation/devicetree/bindings/fb/mmp-disp.txt b/Documentation/devicetree/bindings/fb/mmp-disp.txt new file mode 100644 index 0000000..3cf2903 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/mmp-disp.txt @@ -0,0 +1,71 @@ +* Marvell MMP Display (MMP_DISP) + +To config mmp display, 3 parts are required to be set in dts: +1. mmp fb +Required properties: +- compatible: Should be "marvell,mmp-fb". +- marvell,fb-name: Should be the name of this fb. +- marvell,path-name: Should be the name of path this fb connecting to. +- marvell,overlay-id: Should be the id of overlay this fb is on. +- marvell,dmafetch-id: Should be the dma fetch id this fb using. +- marvell,default-pixfmt: Should be the default pixel format when this fb is +turned on. + +2. mmp controller +Required properties: +- compatible: Should be "marvell,mmp-disp". +- reg: Should be address and length of the register set for this controller. +- interrupts: Should be interrupt of this controller. +- marvell,disp-name: Should be name of this controller +- marvell,path-num: Should be path number exists in this controller. +- marvell,clk-name: Should be name of clock this controller using. + +Required sub-node: +- path: +Required properties in this sub-node: +-- marvell,path-name: Should be name of this path, fb/panel uses this name to +connect to this path. +-- marvell,overlay_num: Should be number of overlay this path has. +-- marvell,output-type: Should be output-type settings +-- marvell,path-config: Should be path-config settings +-- marvell,link-config: Should be link-config settings +-- marvell,rbswap: Should be rbswap settings + +3. panel +Required properties: +- marvell,path-name: Should be path name that this panel connected to. +- other properties each panel has. + +Examples: + +fb: fb { + compatible = "marvell,mmp-fb"; + marvell,fb-name = "mmp_fb"; + marvell,path-name = "mmp_pnpath"; + marvell,overlay-id = <0>; + marvell,dmafetch-id = <1>; + marvell,default-pixfmt = <0x108>; +}; + +disp: disp@d420b000 { + compatible = "marvell,mmp-disp"; + reg = <0xd420b000 0x1fc>; + interrupts = <0 41 0x4>; + marvell,disp-name = "mmp_disp"; + marvell,path-num = <1>; + marvell,clk-name = "LCDCIHCLK"; + path1 { + marvell,path-name = "mmp_pnpath"; + marvell,overlay-num = <2>; + marvell,output-type = <0>; + marvell,path-config = <0x20000000>; + marvell,link-config = <0x60000001>; + marvell,rbswap = <0>; + }; +}; + +panel: <panel-name> { + ... + marvell,path-name = "mmp_pnpath"; + ... +}; diff --git a/drivers/video/mmp/fb/mmpfb.c b/drivers/video/mmp/fb/mmpfb.c index 7ab31eb..e84a411 100644 --- a/drivers/video/mmp/fb/mmpfb.c +++ b/drivers/video/mmp/fb/mmpfb.c @@ -22,6 +22,8 @@ #include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> #include "mmpfb.h" static int var_to_pixfmt(struct fb_var_screeninfo *var) @@ -551,56 +553,86 @@ static void fb_info_clear(struct fb_info *info) fb_dealloc_cmap(&info->cmap); } +#ifdef CONFIG_OF +static const struct of_device_id mmp_fb_dt_match[] = { + { .compatible = "marvell,mmp-fb" }, + {}, +}; +#endif + static int mmpfb_probe(struct platform_device *pdev) { +#ifdef CONFIG_OF + struct device_node *np; +#else struct mmp_buffer_driver_mach_info *mi; +#endif struct fb_info *info = 0; struct mmpfb_info *fbi = 0; - int ret, modes_num; - - mi = pdev->dev.platform_data; - if (mi == NULL) { - dev_err(&pdev->dev, "no platform data defined\n"); - return -EINVAL; - } + int ret = -EINVAL, modes_num; + int overlay_id, dmafetch_id; + const char *path_name; /* initialize fb */ info = framebuffer_alloc(sizeof(struct mmpfb_info), &pdev->dev); if (info == NULL) return -ENOMEM; fbi = info->par; - if (!fbi) { - ret = -EINVAL; + if (!fbi) + goto failed; + +#ifdef CONFIG_OF + np = pdev->dev.of_node; + + if (!np || of_property_read_string(np, + "marvell,fb-name", &fbi->name) || + of_property_read_string(np, + "marvell,path-name", &path_name) || + of_property_read_u32(np, + "marvell,overlay-id", &overlay_id) || + of_property_read_u32(np, + "marvell,dmafetch-id", &dmafetch_id) || + of_property_read_u32(np, + "marvell,default-pixfmt", &fbi->pix_fmt)) { + dev_err(&pdev->dev, "unable to get fb setting from dt\n"); goto failed; } +#else + mi = pdev->dev.platform_data; + if (mi == NULL) { + dev_err(&pdev->dev, "no platform data defined\n"); + goto failed; + } + fbi->name = mi->name; + path_name = mi->path_name; + overlay_id = mi->overlay_id; + dmafetch_id = mi->dmafetch_id; + fbi->pix_fmt = mi->default_pixfmt; +#endif /* init fb */ fbi->fb_info = info; platform_set_drvdata(pdev, fbi); fbi->dev = &pdev->dev; - fbi->name = mi->name; - fbi->pix_fmt = mi->default_pixfmt; pixfmt_to_var(&info->var, fbi->pix_fmt); mutex_init(&fbi->access_ok); /* get display path by name */ - fbi->path = mmp_get_path(mi->path_name); + fbi->path = mmp_get_path(path_name); if (!fbi->path) { - dev_err(&pdev->dev, "can't get the path %s\n", mi->path_name); - ret = -EINVAL; + dev_err(&pdev->dev, "can't get the path %s\n", path_name); goto failed_destroy_mutex; } dev_info(fbi->dev, "path %s get\n", fbi->path->name); /* get overlay */ - fbi->overlay = mmp_path_get_overlay(fbi->path, mi->overlay_id); - if (!fbi->overlay) { - ret = -EINVAL; + fbi->overlay = mmp_path_get_overlay(fbi->path, overlay_id); + if (!fbi->overlay) goto failed_destroy_mutex; - } + /* set fetch used */ - mmp_overlay_set_fetch(fbi->overlay, mi->dmafetch_id); + mmp_overlay_set_fetch(fbi->overlay, dmafetch_id); modes_num = modes_setup(fbi); if (modes_num < 0) { @@ -679,6 +711,7 @@ static struct platform_driver mmpfb_driver = { .driver = { .name = "mmp-fb", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mmp_fb_dt_match), }, .probe = mmpfb_probe, }; diff --git a/drivers/video/mmp/hw/mmp_ctrl.c b/drivers/video/mmp/hw/mmp_ctrl.c index 8621a9f..19d68bc 100644 --- a/drivers/video/mmp/hw/mmp_ctrl.c +++ b/drivers/video/mmp/hw/mmp_ctrl.c @@ -37,6 +37,8 @@ #include <linux/uaccess.h> #include <linux/kthread.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_device.h> #include "mmp_ctrl.h" @@ -396,26 +398,57 @@ static void path_set_default(struct mmp_path *path) writel_relaxed(tmp, ctrl_regs(path) + dma_ctrl(0, path->id)); } -static int path_init(struct mmphw_path_plat *path_plat, - struct mmp_mach_path_config *config) +static int path_init(struct mmphw_path_plat *path_plat, void *arg) { struct mmphw_ctrl *ctrl = path_plat->ctrl; struct mmp_path_info *path_info; struct mmp_path *path = NULL; - - dev_info(ctrl->dev, "%s: %s\n", __func__, config->name); +#ifdef CONFIG_OF + struct device_node *path_np = arg; +#else + struct mmp_mach_path_config *config = arg; +#endif /* init driver data */ path_info = kzalloc(sizeof(struct mmp_path_info), GFP_KERNEL); if (!path_info) { - dev_err(ctrl->dev, "%s: unable to alloc path_info for %s\n", - __func__, config->name); - return 0; + dev_err(ctrl->dev, "%s: unable to alloc path_info\n", + __func__); + return -ENOMEM; + } + +#ifdef CONFIG_OF + if (!path_np || of_property_read_string(path_np, "marvell,path-name", + &path_info->name) || + of_property_read_u32(path_np, "marvell,overlay-num", + &path_info->output_type) || + of_property_read_u32(path_np, "marvell,output-type", + &path_info->overlay_num)) { + dev_err(ctrl->dev, "%s: unable to get path setting from dt\n", + __func__); + kfree(path_info); + return -EINVAL; } + /* allow these settings not set */ + of_property_read_u32(path_np, "marvell,path-config", + &path_plat->path_config); + of_property_read_u32(path_np, "marvell,link-config", + &path_plat->link_config); + of_property_read_u32(path_np, "marvell,rbswap", + &path_plat->dsi_rbswap); +#else path_info->name = config->name; + path_info->overlay_num = config->overlay_num; + path_info->output_type = config->output_type; + path_plat->path_config = config->path_config; + path_plat->link_config = config->link_config; + path_plat->dsi_rbswap = config->dsi_rbswap; +#endif + + dev_info(ctrl->dev, "%s: %s\n", __func__, path_info->name); + path_info->id = path_plat->id; path_info->dev = ctrl->dev; - path_info->overlay_num = config->overlay_num; path_info->overlay_ops = &mmphw_overlay_ops; path_info->set_mode = path_set_mode; path_info->plat_data = path_plat; @@ -424,16 +457,13 @@ static int path_init(struct mmphw_path_plat *path_plat, path = mmp_register_path(path_info); if (!path) { kfree(path_info); - return 0; + return -EINVAL; } path_plat->path = path; - path_plat->path_config = config->path_config; - path_plat->link_config = config->link_config; - path_plat->dsi_rbswap = config->dsi_rbswap; path_set_default(path); kfree(path_info); - return 1; + return 0; } static void path_deinit(struct mmphw_path_plat *path_plat) @@ -445,13 +475,25 @@ static void path_deinit(struct mmphw_path_plat *path_plat) mmp_unregister_path(path_plat->path); } +#ifdef CONFIG_OF +static const struct of_device_id mmp_disp_dt_match[] = { + { .compatible = "marvell,mmp-disp" }, + {}, +}; +#endif + static int mmphw_probe(struct platform_device *pdev) { - struct mmp_mach_plat_info *mi; struct resource *res; - int ret, i, size, irq; + int ret, i, size, irq, path_num; + const char *clk_name, *disp_name; struct mmphw_path_plat *path_plat; struct mmphw_ctrl *ctrl = NULL; +#ifdef CONFIG_OF + struct device_node *np, *path_np = NULL; +#else + struct mmp_mach_plat_info *mi; +#endif /* get resources from platform data */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -468,6 +510,22 @@ static int mmphw_probe(struct platform_device *pdev) goto failed; } +#ifdef CONFIG_OF + np = pdev->dev.of_node; + + if (!np || of_property_read_u32(np, + "marvell,path-num", &path_num) || + of_property_read_string(np, + "marvell,disp-name", &disp_name) || + of_property_read_string(np, + "marvell,clk-name", &clk_name) || + of_get_child_count(np) != ctrl->path_num) { + dev_err(&pdev->dev, "%s: failed to get settings from dt\n", + __func__); + ret = -EINVAL; + goto failed; + } +#else /* get configs from platform data */ mi = pdev->dev.platform_data; if (mi == NULL || !mi->path_num || !mi->paths) { @@ -476,17 +534,21 @@ static int mmphw_probe(struct platform_device *pdev) goto failed; } - /* allocate */ + disp_name = mi->name; + path_num = mi->path_num; + clk_name = mi->clk_name; +#endif + + /* allocate ctrl */ size = sizeof(struct mmphw_ctrl) + sizeof(struct mmphw_path_plat) * - mi->path_num; + path_num; ctrl = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); if (!ctrl) { ret = -ENOMEM; goto failed; } - - ctrl->name = mi->name; - ctrl->path_num = mi->path_num; + ctrl->path_num = path_num; + ctrl->name = disp_name; ctrl->dev = &pdev->dev; ctrl->irq = irq; platform_set_drvdata(pdev, ctrl); @@ -521,9 +583,9 @@ static int mmphw_probe(struct platform_device *pdev) } /* get clock */ - ctrl->clk = devm_clk_get(ctrl->dev, mi->clk_name); + ctrl->clk = devm_clk_get(ctrl->dev, clk_name); if (IS_ERR(ctrl->clk)) { - dev_err(ctrl->dev, "unable to get clk %s\n", mi->clk_name); + dev_err(ctrl->dev, "unable to get clk %s\n", clk_name); ret = -ENOENT; goto failed; } @@ -539,11 +601,16 @@ static int mmphw_probe(struct platform_device *pdev) path_plat->id = i; path_plat->ctrl = ctrl; - /* path init */ - if (!path_init(path_plat, &mi->paths[i])) { - ret = -EINVAL; + /* path init from mach info or dt */ +#ifdef CONFIG_OF + path_np = of_get_next_child(np, path_np); + ret = path_init(path_plat, path_np); +#else + ret = path_init(path_plat, &mi->paths[i]); +#endif + + if (ret) goto failed_path_init; - } } #ifdef CONFIG_MMP_DISP_SPI @@ -573,6 +640,7 @@ static struct platform_driver mmphw_driver = { .driver = { .name = "mmp-disp", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mmp_disp_dt_match), }, .probe = mmphw_probe, }; -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-fbdev" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html